【问题标题】:Like Operator Searching so Slow像运算符搜索这么慢
【发布时间】:2017-02-07 09:23:56
【问题描述】:

我有一个查询,它正在从表中搜索结果,如果一行与特定对象匹配,它将提供结果。

所以,它是一个 12 个字母的数字。

所以功能是如果用户提供一个数字为 414。它会像“%414%”一样搜索。

如果数字的长度超过 6 位,它将搜索“4146144%”

因此查询变得越来越慢,因为我们有 2000 万条记录。

能否请您提供任何替代方法来解决该问题。

公司不允许使用任何 API 或其他任何东西。

 SELECT  distinct TOP (15) bt_id AS [Key]
       , UPPER(rtrim(ltrim(bt_id)))+' - '+UPPER(rtrim(ltrim(bt_desc))) AS [Description]   
 FROM    fcbillto 
 WHERE   bt_id   like '%' + @SearchTerm + '%'
 OR      bt_desc like '%' + @SearchTerm + '%'

如果全文扫描是解决方案,那么我可以为单个表创建两个不同的目录,因为上面是我需要搜索的列之一,而在其他情况下,我正在搜索同一个表的其他列。所以,我需要创建两个存储库。

【问题讨论】:

  • 是 bt_desc ntext 吗?您真的需要搜索描述中的数字,还是仅在 bt_id 中搜索就足够准确?
  • 两者都是数据类型 char,Bt_id char(12) 和 bt_desc 是 char(40)。由于数据库设计较早,所以我无法更新设计部分
  • 正确的索引是加快速度的一种方法:this,或者可能是 thisthis 的副本
  • @dlatikay: 再多的索引都无法通过LIKE '%414%' 搜索(带有前导% 通配符)加快查询速度——这些总是全表扫描,因此速度很慢...... ...

标签: sql-server sql-server-2008 tsql


【解决方案1】:

您有两个问题妨碍了有效使用任何索引作为您的查询代表:

1) OR 子句。 SQL 不能在 bt_idbt_desc 上使用带有 OR 子句的索引,因为使用索引过滤一个列可能会剔除符合另一列谓词的有效行。如果您在两列上都有索引,则可以使用UNION 来获取满足这两个条件的行(或者如果您很幸运,优化器可能会在后台执行此操作)但索引可能不会用作事物坚持是因为……

2) 带有前导 %LIKE 无法在索引上查找,因为索引是根据前导字符排序的。如果它必须在字符串中间寻找字符,那么它就不能使用索引来寻找行。 (这并不意味着它不会扫描索引,因为它比表本身小 - 因此在此基础上可能仍有性能改进)。

因此,如果不改变需求,可能很难看到真正的性能改进。如果您可以更改要求,以便仅搜索前导字符(或将查询限制在另一个索引列上),那么这将更快(假设索引在 bt_idbt_desc):

SELECT  TOP (15) bt_id AS [Key]
   ,  UPPER(rtrim(ltrim(bt_id)))+' - '+UPPER(rtrim(ltrim(bt_desc))) AS [Description]   

FROM 
(SELECT  bt_id
   , bt_desc 
 FROM    fcbillto 
 WHERE   bt_id   like @SearchTerm + '%'

UNION

SELECT  bt_id
   , bt_desc   
 FROM    fcbillto 
 WHERE   bt_desc like @SearchTerm + '%') search

ORDER BY bt_id -- I presume?

全文索引旨在搜索列中的单词 - 你只有字符,所以没有帮助。

【讨论】:

  • 我相信这个联合解决方案比问题中的查询慢,因为查询之前的慢联合已经消除了前15行之外的其余行
  • 这取决于ORDER BY 的需要。我添加了一个假设它是相关的。如果需要,那么原始查询无论如何都必须扫描整个表以确定哪些行构成前 15 行。如果不是,则原始查询可能会更快,具体取决于满足条件的行所在的位置。然而,这将涉及聚集索引扫描,这对锁定有可怕的影响。
【解决方案2】:

试试这个。

SELECT distinct TOP (15) 
  bt_id AS [Key], 
  UPPER(rtrim(ltrim(bt_id)))+' - '+UPPER(rtrim(ltrim(bt_desc))) AS [Description] 
FROM fcbillto 
WHERE charindex(@SearchTerm, bt_id) > 0 OR charindex(@SearchTerm, bt_desc) > 0 

【讨论】:

  • 谢谢 Saravanan 能否提供功能名称。喜欢它不像其他东西。这样我就可以在实施之前了解它的优缺点,并可以就此向我的前辈提出建议。
  • 但是:charindex(@SearchTerm, bt_id) > 0 与 '%@SearchTerm%' 之类的 url 的作用相同,但在内部它们的工作方式有所不同。对于一些人来说,LIKE 表达式的结果更快,对于其他人来说,CHARINDEX 方法。也许这取决于查询、处理器数量、操作系统等等。可能值得一试。请把这个给你的长辈看。 cc.davelozinski.com/sql/…
  • 这是一个有趣的链接,但它适用于对单个列的搜索。它也不希望使用索引(它查看字符串的两端),因此纯粹是测试功能 - 而不是使用索引来提高性能。当前的问题在于查询导致对 2000 万行表进行表/聚集索引扫描,因此除非可以应用某种索引使用,否则将对性能产生一些非常负面的影响(尤其是锁定!)。
猜你喜欢
  • 2013-04-11
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
  • 1970-01-01
  • 2017-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多