2

我的数据库中有一个维度表变得太大。我的意思是它有太多的记录——超过一百万——因为它的增长速度与关联的事实相同。这主要是由于设计不好,我正在尝试清理它。

我尝试做的一件事是删除不再使用的维度记录。定期维护事实表并删除旧快照。因为维度不是这样维护的,所以表中有许多行的主键值不再出现在任何链接的事实表中。所有事实表都有外键约束。

有没有办法找到主键值不再出现在与外键约束链接的任何表中的表行?

我试着写一个脚本来跟踪这个。基本上是这样的:

select key from dimension 
where not exists (select 1 from fact1 where fk = pk) 
and not exists (select 1 from fact2 where fk = pk) 
and not exists (select 1 from fact3 where fk = pk)

但是对于很多链接表,这个查询会在一段时间后消失——至少,我的管理工作室崩溃了。所以我不确定是否还有其他选择。

4

2 回答 2

1

我们不得不在我的一位客户身上做类似的事情。查询,就像你的“不存在......并且不存在......并且不存在......”在我们改变我们的策略以在大约 20 分钟内处理它之前需要大约 22 小时才能运行。

正如 Nsousa 建议的那样,您必须拆分查询,这样 SQL Server 就不必一次性处理所有数据,不必使用 tempdb 和所有其他东西。

首先,创建一个包含所有键的新表。创建此表的原因是不必为每个查询读取全表扫描,在 8k 页面上有更多键,并在每次删除后处理越来越小的键集。

create table DimensionkeysToDelete (Dimkey char(32) primary key nonclustered);
insert into DimensionkeysToDelete 
select key from dimension order by key; 

然后,不是删除未使用的键,而是删除事实表中存在的键,从行数最少的事实表开始。确保事实表具有适当的索引以提高性能。

delete from DimensionkeysToDelete 
from DimensionkeysToDelete d 
inner join fact1 on f.fk = d.Dimkey;

delete from DimensionkeysToDelete 
from DimensionkeysToDelete d 
inner join fact2 on f.fk = d.Dimkey;

delete from DimensionkeysToDelete 
from DimensionkeysToDelete d 
inner join fact3 on f.fk = d.Dimkey;

完成所有事实表后,DimensionkeysToDelete 中仅保留未使用的键。要回答您的问题,只需在此表上执行选择以获取该特定维度的所有未使用键,或将其与维度连接以获取数据。

但是,据我了解您需要清理仓库,使用此表从原始维度表中删除。在这一步,您可能还需要为审计目的采取一些措施(即:在审计表中插入 'Key' + key + ' deleted on + convert(datetime, getdate(),121) + ' by script X'.. ..)

我认为这可以优化,看一下执行计划,但是我的客户对此很满意,所以我们不必为此付出太多努力。

于 2020-09-05T15:30:48.697 回答
0

您可能希望将其拆分为不同的查询。检查 fact1 中未使用的行,然后分别检查 fact2 等。然后将所有这些结果相交以获取所有事实表中未使用的行。

我还建议使用左外连接而不是嵌套查询,计算事实表中每个 pk 的行数,并从结果集中过滤掉那些计数不为零的行。

您的查询会很困难,因为它会同时扫描每个事实表。

于 2020-09-04T16:00:58.493 回答