如何提高使用 LIKE %abc 的 where 子句的性能?

HCh*_* Le 5 performance index sql-server select like

我有下面的 select 语句,结果非常慢(41 秒)

SELECT DISTINCT a.Doc_Resource_ID 
       ,a.Parent_ID 
       ,a.Logical_Path 
       ,a.lvl 
       ,CAST(SUBSTRING(a.Security_Level, 21, 1) AS TINYINT)
  FROM Doc_ACL_Detail_D a   
 WHERE a.UserId = @I_vUserId 
   AND @I_vParentId = 0 
    OR (Logical_Path LIKE(CASE 
                             WHEN @I_vParentId>0 THEN '%-'+LTRIM(STR(@I_vParentId)) 
                          END)
    OR Logical_Path LIKE(CASE 
                            WHEN @I_vParentId>0 THEN '%-'+LTRIM(STR(@I_vParentId))+'-%' 
                         END ))
OPTION (MAXRECURSION 5000)
Run Code Online (Sandbox Code Playgroud)

我已经为表创建了非聚集索引Doc_ACL_Detail_D,但执行计划仍然是表扫描。

我创建的索引:

    CREATE NONCLUSTERED INDEX idx_Doc_ACL_Detail_D_UserId_Logical_Path 
       ON [dbo].[Doc_ACL_Detail_D] ([UserId],[Logical_Path])
  INCLUDE (Parent_ID,Doc_Resource_ID,lvl,Security_Level)
Run Code Online (Sandbox Code Playgroud)

有人可以帮我优化这个语句吗?十分感谢。

Phi*_* W. 17

就目前的数据而言,没有任何索引可以提供帮助。
您要查找的值嵌入在字段内的某个位置,而不是在字段的开头(索引可以提供帮助)。由于数据库不知道字段开头内容,因此它无法导航到索引的正确位以获取所需的记录。

反转值并对这些值建立索引将有助于值位于字段末尾的位置,但仍然无助于值卡在中间某处的位置。

对我来说,这个领域的数据“太多”了。您正在使用字符串操作函数来提取部分值,这对我来说,您真正想要的值被“包装”在“噪声”中。 消除噪音可能是一个更好的选择。

select * 
from Folders ; 

+----+--------+------+
| id | parent | path | 
+----+--------+------+
|  1 |  NULL  | abc  | The folder /abc 
|  2 |      1 | def  |            /abc/def 
|  3 |      2 | ghi  |            /abc/def/ghi 
+----+--------+------+
Run Code Online (Sandbox Code Playgroud)

递归地遍历这个结构要容易得多

另外,请考虑删除distinct.
我经常看到,distinct 被用作“膏药”来掩盖数据结构本身或查询的潜在问题,例如结果中出现的“重复”行(通常是由错误的联接引起的),但是“使用不同的东西会让它们消失”。摆脱这些“重复项”可能会对数据库造成巨大的消耗(“选择不同的 a,b,c,d”的表现与“按 a,b,c,d 排序 a,b,c, d"),所以最好解决根本原因。