喜欢在SQL中解决(性能问题)

Jon*_*onn 6 sql t-sql sql-server sql-like

我一直在阅读,发现使用LIKE导致查询大幅减速.

一位同事建议我们使用

Select Name
From mytable
a.Name IN (SELECT Name 
           FROM mytable
           WHERE Name LIKE '%' + ISNULL(@Name, N'') + '%' 
           GROUP BY Name)
Run Code Online (Sandbox Code Playgroud)

替代

Select Name
From mytable
a.Name LIKE '%' + ISNULL(@Name, N'') + '%'
Run Code Online (Sandbox Code Playgroud)

现在我不是SQL专家,我不太了解这些陈述的内部运作.这是一个更好的选择,值得为每个类似的声明键入一些额外的字符吗?是否有更好的(更容易打字)替代方案?

OMG*_*ies 9

有几个性能问题要解决......

如果可能,请不要多次访问同一个表

不要将子查询用于可以在不需要引用同一个表的其他副本的情况下完成的条件.如果由于使用聚合函数(MAX,MIN等)而需要来自表副本的数据,这是可以接受的,尽管分析函数(ROW_NUMBER,RANK等)可能更容易(假设支持).

不要比较你不需要的东西

如果您的参数为NULL,这意味着您想要比较的列的任何值,请不要包含过滤条件.这些陈述:

WHERE a.Name LIKE '%' + ISNULL(@Name, N'') + '%'
Run Code Online (Sandbox Code Playgroud)

...保证优化器必须比较name列的值,通配符与否.更糟糕的LIKE是,在评估的左侧,通配符确保如果搜索的列中存在索引,则无法使用索引.

表现更好的方法是:

IF @Name IS NOT NULL 
BEGIN
   SELECT ...
     FROM ...
    WHERE a.name LIKE '%' + @Name + '%'
END
ELSE 
BEGIN
   SELECT ...
     FROM ...
END
Run Code Online (Sandbox Code Playgroud)

表现良好的SQL就是要根据你的需要定制.当您有两个或更多独立条件的查询时,这就是您应该考虑动态SQL的原因.

使用正确的工具

LIKE当您检查文本数据中是否存在字符串时,运算符在搜索文本时效率不高. 全文搜索(FTS)技术旨在解决这些缺点:

IF @Name IS NOT NULL
BEGIN
   SELECT ...
     FROM ...
    WHERE CONTAINS(a.name, @Name) 
END
ELSE
BEGIN
   SELECT ...
     FROM ...
END
Run Code Online (Sandbox Code Playgroud)

始终测试和比较

我同意LittleBobbyTables - 解决方案最终依赖于检查所有备选方案的查询/执行计划,因为表格设计和数据会影响优化程序的决策和性能.在SQL Server中,具有最低子树的算法效率最高,但如果不维护表统计信息和索引,它可以随时间变化.


Lit*_*les 8

只需比较执行计划,您就应该看到差异.

我没有您的确切数据,但我针对我的SQL Server 2005数据库运行了以下查询(是的,这是书呆子):

SELECT     UnitName
FROM         Units
WHERE     (UnitName LIKE '%Space Marine%')

SELECT     UnitName
FROM         Units
WHERE     UnitName IN (
   (SELECT UnitName FROM Units 
   WHERE UnitName LIKE '%Space Marine%' GROUP BY UnitName)
)
Run Code Online (Sandbox Code Playgroud)

这是我的执行计划结果:

替代文字

正如您在上面所看到的,您的同事的建议会在我的查询中添加嵌套循环和第二个聚簇索引扫描.您的里程可能会有所不同,但一定要检查执行计划,看看他们的比较方式.我无法想象它会如何更有效率.