【发布时间】:2013-03-21 21:10:19
【问题描述】:
我正在重写旧的遗留系统。它有一个名为checkExisting() 的函数。旧系统使用查询从 MSSQL 数据库中提取对象,如下所示(使用 ADO DB):
SELECT ObjectId, Name.....
FROM tblRegisteredIncludes
WHERE UPPER("Name") IN ('PROGA.H', 'PROGB.H'............... list)
有很多像tblRegisteredIncludes 这样的表,但是 SQL 是按表名分组的,并且使用带有对象名称列表的 IN 子句。
这执行得很快,因为 SQL Server 在一次扫描中收集了所有对象,并且在表中的 Name 列上有一个索引。
但是,在新系统中,我不能使用相同的 SQL,因为WHERE 条件更复杂。它还使用 Source 字段,有时还使用条件中的其他字段。我有大量的单个 SQL 查询:
SELECT ObjectId, Name..... FROM tblRegisteredIncludes
WHERE UPPER("Name") = 'PROGA.H' AND UPPER("Source") = "..."
SELECT ObjectId, Name..... FROM tblRegisteredIncludes
WHERE UPPER("Name") = ('PROGB.H') AND UPPER("Source") = "..."
我已将tblRegisteredIncludes 表中的名称索引替换为(Name,Source) 上的复合索引。
即使如此,我也预计 SQL 的总执行速度会慢一些,但不会超过 15-20%。相反,它要慢得多,有时甚至高达 100%。我尝试使用 UNION ALL 将 SQL 组合到一个大型 SQL 查询中:
SELECT ObjectId, Name..... FROM tblRegisteredIncludes
WHERE UPPER("Name") = 'PROGA.H' AND UPPER("Source") = "..."
UNION ALL
SELECT ObjectId, Name..... FROM tblRegisteredIncludes
WHERE UPPER("Name") = ('PROGB.H') AND UPPER("Source") = "..."
然后再处理生成的 ADO DB 记录集,但速度更慢!
我想知道是否有一些有效的方法可以更快地执行这些查询?在使用 IN 子句和名称列表时,我需要达到与旧案例类似的性能。我可以提供执行计划。
【问题讨论】:
-
我想看看执行计划。你为什么使用
upper?您是否检查过排序规则是否区分大小写? -
您能否详细说明“我不能使用相同的 SQL,因为 WHERE 条件更复杂。”在您给出的示例中,没有理由将查询分开。
-
你真的需要UPPER吗?出于这个原因,很少使用区分大小写的排序规则。使用 UPPER 会破坏您的查询计划,因为该函数对 SQL Server 是不透明的 - 它不知道该函数的作用,因此它不会使用索引并进行表扫描。
-
在两边都使用 Upper 可能是问题之一:WHERE UPPER("Name") = ('PROGB.H') AND UPPER("Source") = "...".. . 在Oracle 中,当转换为Upper/Lower 时,可以创建基于函数的索引。不确定在 SQL Server 中是否有同样的可能。
-
@lserni 肯定 PERSISTED 计算列会比通过触发器保持列更新更好?例如
CREATE TABLE T (A VARCHAR(50) COLLATE Latin1_general_cs_as NOT NULL, B AS A COLLATE Latin1_general_ci_as PERSISTED, C AS LOWER(A) PERSISTED)
标签: sql sql-server performance union