如何在维度 table 中查找未使用的行

How to find unused rows in a dimension table

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

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

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

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

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)

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

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

中未使用的行

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

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

我们不得不在我的一个客户身上做类似的事情。在我们更改策略以在 ~20 内处理此问题之前,像您的查询一样,“不存在......且不存在......且不存在......”需要约 22 小时才能 运行分钟。

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

首先,创建新的 table,其中包含所有密钥。创建这个 table 的原因是不必为每个查询读取完整的 table 扫描,在 8k 页面上有更多的键,并且在每次删除后处理越来越小的键集。

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

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

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;

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

但是,据我了解您需要清理您的仓库,使用此table 从原始维度table 中删除。在此步骤中,您可能还需要采取一些措施来进行审计(即:插入审计 table 'Key ' + key + ' deleted on + convert(datetime, getdate(),121) + '通过脚本 X'.... )

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