【发布时间】:2011-01-24 05:14:54
【问题描述】:
我在以 2000 兼容模式运行的 SQL 2005 Server 上有一个充满数据的表 ItemValue,看起来类似于(它是一个用户定义的值表):
ID ItemCode FieldID Value
-- ---------- ------- ------
1 abc123 1 D
2 abc123 2 287.23
4 xyz789 1 A
5 xyz789 2 3782.23
6 xyz789 3 23
7 mno456 1 W
9 mno456 3 45
... and so on.
FieldID 来自 ItemField 表:
ID FieldNumber DataFormatID Description ...
-- ----------- ------------ -----------
1 1 1 Weight class
2 2 4 Cost
3 3 3 Another made up description
. . x xxx
. . x xxx
. . x xxx
x 91 (we have 91 user-defined fields)
因为我无法在 2000 模式下进行 PIVOT,所以我们无法使用 CASE 和 GROUP BY 构建一个丑陋的查询,以获取数据以查看它应该如何用于某些旧版应用程序,即:
ItemNumber Field1 Field2 Field3 .... Field51
---------- ------ ------- ------
abc123 D 287.23 NULL
xyz789 A 3782.23 23
mno456 W NULL 45
你可以看到我们只需要这个表来显示直到第 51 个 UDF 的值。这是查询:
SELECT
iv.ItemNumber,
,MAX(CASE WHEN f.FieldNumber = 1 THEN iv.[Value] ELSE NULL END) [Field1]
,MAX(CASE WHEN f.FieldNumber = 2 THEN iv.[Value] ELSE NULL END) [Field2]
,MAX(CASE WHEN f.FieldNumber = 3 THEN iv.[Value] ELSE NULL END) [Field3]
...
,MAX(CASE WHEN f.FieldNumber = 51 THEN iv.[Value] ELSE NULL END) [Field51]
FROM ItemField f
LEFT JOIN ItemValue iv ON f.ID = iv.FieldID
WHERE f.FieldNumber <= 51
GROUP BY iv.ItemNumber
当 FieldNumber 约束为
SELECT <== Computer Scalar <== Stream Aggregate <== Sort (Cost: 70%) <== Hash Match <== (Clustered Index Seek && Table Scan)
而且速度很快!我可以在大约一秒钟内拉回 100,000+ 条记录,这符合我们的需求。
但是,如果我们有更多的 UDF,并且我将约束更改为 66 以上的任何内容(是的,我对它们进行了一项一项测试),或者如果我完全删除它,我会在执行中丢失排序计划,然后它被一大堆收集、重新分区和分发流的并行块所取代,整个过程很慢(即使只有 1 条记录也需要 30 秒)。
FieldNumber 有一个聚集的唯一索引,并且是 ItemField 中具有 ID 列(非聚集索引)的复合主键的一部分强>表。 ItemValue 表的 ID 和 ItemNumber 列构成一个 PK,ItemNumber上有一个额外的非聚集索引> 栏目。
这背后的原因是什么?为什么更改我的简单整数约束会更改整个执行计划?
如果你能做到……你会采取什么不同的做法?计划在几个月后升级 SQL,但我需要在此之前解决这个问题。
【问题讨论】:
-
我会做不同的事情是不使用该表结构。对于 99% 的数据需求,使用具有已定义字段的结构比使用 EAV 表要好得多。顺便说一句,兼容模式不会阻止您使用新功能,它是允许使用不再被允许的功能。但是,如果您在 2005 数据库和 2000 生产数据库上进行开发,最好避免使用新功能。
标签: sql sql-server query-optimization sql-execution-plan