我正在重写一个旧的遗留系统。它有一个名为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查询中组合SQLSELECT 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子句和名称列表时,我需要达到与旧案例类似的性能。我可以提供执行计划。
答案 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
. . .
如果您的所有比较都在Name
和Source
,我建议您使用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'