SQL Union All太慢了

时间:2013-03-21 12:10:02

标签: sql sql-server performance union

我正在重写一个旧的遗留系统。它有一个名为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子句和名称列表时,我需要达到与旧案例类似的性能。我可以提供执行计划。

2 个答案:

答案 0 :(得分:2)

union all版本中,每个子查询都会对表格进行单独扫描。

您应该使用or条件引入所有行:

SELECT ObjectId, Name.....
FROM tblRegisteredIncludes   
WHERE (UPPER("Name") = 'PROGA.H' AND UPPER("Source") = "...") or
      (UPPER("Name") = ('PROGB.H') AND UPPER("Source") = "...") or
      . . .

如果您的所有比较都在NameSource,我建议您使用CTE即时创建表:

with toinclude as (
   select 'PROGA.H' as name, 'SOURCE' as source union all
   select . . .
)
select ri.ObjectId, ri.Name
from tblRegisteredIncludes join
     toinclude
     on ri.name = toinclude.name and ri.source = toinclude.source

除非您特别担心您的实现或字段已覆盖默认的不区分大小写的行为,否则您可以忽略toupper()。在where子句中使用函数通常会阻止使用索引。

答案 1 :(得分:0)

根据您的描述,我假设该表有非常多的行,在这种情况下几乎可以肯定是UPPER导致速度问题,因为这意味着它无法正确使用您认为正确的索引组。存储的数据是否区分大小写? - 检查数据库设置,默认情况下通常不会删除UPPER。

如果它区分大小写,那么如果存储的名称的大小写是一致的,你仍然可以删除Upper,只需使用大小写一致的大小写,例如: Name ='ProgB.H'