【发布时间】:2011-08-27 22:54:11
【问题描述】:
我有以下查询(为清楚起见稍作修改):
CREATE PROCEDURE Kctc.CaseTasks_GetCaseTasks
@CaseNumber int
... other parameters
,@ChangedBefore datetime
,@ChangedAfter datetime
AS
SELECT Kctc.CaseTasks.CaseTaskId
...blah blah blah
FROM Kctc.CaseTasks
... some joins here
WHERE
... some normal where clauses
AND
(
(@ChangedAfter IS NULL AND @ChangedBefore IS NULL)
OR
EXISTS (SELECT *
FROM Kctc.FieldChanges
WHERE Kctc.FieldChanges.RecordId = Kctc.CaseTasks.CaseTaskId AND
Kctc.FieldChanges.TableName = 'CaseTasks' AND
Kctc.FieldChanges.DateOfChange BETWEEN
ISNULL(@ChangedAfter, '2000/01/01') AND
ISNULL(@ChangedBefore, '2050/01/01'))
)
只要用户为@ChangedBefore 或@ChangedAfter 指定值,此查询就会超时,因此会调用子查询。
子查询检查表中是否存在名为FieldChanges 的记录(它有效地记录了CaseTasks 表中每个字段的更改)。
查询FieldChanges 效率不高,因为它涉及对未编入索引的文本字段TableName 进行过滤。而且我知道子查询本质上是低效的。
所以我的一般问题是,有没有办法重新设计查询以使其性能更好?
当有多个关联的FieldChanges(即保留 EXISTS 语义)时,我想不出一种方法可以将子查询表示为连接,同时仍然只返回一个 CaseTask 行。我还没有索引FieldChanges 表的TableName 字段,因为我对索引文本字段犹豫不决。
那我该怎么办?
【问题讨论】:
-
顺便说一句,我可以看到可能需要审查数据库的设计,因为它似乎无法应对当前的数据量。但我的问题是关于查询的设计,而不是数据库的设计。
-
我们在查看 CaseTasks 和 FieldChanges 的行数。还有你目前有什么样的索引。
-
最好的办法是评估查询计划。这将告诉您是否正在执行您不希望执行的全表扫描。
标签: sql-server performance tsql subquery where-clause