【发布时间】:2020-03-07 23:36:56
【问题描述】:
软件会生成很多这样的非最佳查询:
SELECT
<List of Columns>
FROM <Table>
WHERE(
([COL1] = UPPER('CONST_VALUE') AND [COL2] = UPPER('v1')) OR
([COL1] = UPPER('CONST_VALUE') AND [COL2] = UPPER('v2')) OR
([COL1] = UPPER('CONST_VALUE') AND [COL2] = UPPER('v4')) OR
([COL1] = UPPER('CONST_VALUE') AND [COL2] = UPPER('v6')) OR
([COL1] = UPPER('CONST_VALUE') AND [COL2] = UPPER('v8')) OR
<...>
)
执行计划:https://www.brentozar.com/pastetheplan/?id=rJGtaBzSU
执行此查询会导致执行索引查找大约需要 1 秒。将查询重构为以下语句导致执行时间为 3ms:
SELECT
<List of Columns>
FROM <Table>
WHERE([COL1] = UPPER('CONST_VALUE') AND (
[COL2] = UPPER('v1') OR
[COL2] = UPPER('v2') OR
[COL2] = UPPER('v4') OR
[COL2] = UPPER('v6') OR
[COL2] = UPPER('v8') OR
<...>
))
索引看起来最佳 afaik,COL1 和 COL2 上的索引包括所有选定的其他列。由于我们暂时无法更改软件,有没有办法加快执行时间?添加不同类型的索引。我也在考虑查询重写之类的东西,但是在SQL Server中找不到这样的东西。
【问题讨论】:
-
您可以使用
in运算符。像where col1='const_value' and col2 in ('v1','v2','v3')这样的东西。它可读性更好,但在内部编译到您的第二个示例中。 -
如果您无法更改查询,您的选择将受到限制。您是否尝试过关于 COL 的索引!和 COL2 与
- 作为包含的列?
-
您检查过实际执行计划吗?请参阅paste the plan,了解在您的问题中包含执行计划的方法。指数统计数据是最新的吗?请参阅
update statistics了解更多信息。 -
是
UPPER的使用导致了问题,否则它会很好地折叠谓词。由于某种原因,它不会不断折叠该函数,并且可能只是将其视为对UPPER('000049')的不同引用可能不会评估为同一事物 -
问题在于,如果没有不断的折叠,它就不能盲目地重复搜索。 UPPER('a') 和 UPPER('A') 都评估为相同的值,但不应该返回的匹配行加倍。所以它需要一个重复删除的步骤。您的手动重写使用合并间隔来完成。当两列可能不同时,不确定这是否不可用
标签: sql sql-server tsql query-performance