【问题标题】:T-SQL speed comparison between LEFT() vs. LIKE operatorLEFT() 与 LIKE 运算符之间的 T-SQL 速度比较
【发布时间】:2011-05-03 01:08:48
【问题描述】:

我正在创建基于某些 nvarchar 列的第一个字母的结果分页,而不是通常的结果分页,通常按结果数分页。

我没有遇到过是否使用LIKE 运算符或相等 (=) 运算符过滤结果的挑战。

select *
from table
where name like @firstletter + '%'

对比

select *
from table
where left(name, 1) = @firstletter

我已经尝试在网上搜索两者之间的速度比较,但很难找到任何结果,因为大多数搜索结果与LEFT JOINs而不是LEFT函数有关。

【问题讨论】:

  • 您是否查看过两者的查询计划?您是否运行过自己的基准测试?
  • 不,我没有。我想我不是第一个问自己这个问题的人,所以我认为其他人可能已经测试过了。由于 LEFT 主要与连接有关,我似乎无法找到这些数据。因此,如果有人在某处有链接的问题。我怀疑 LEFT 应该更快
  • 第一个(使用LIKE)有机会在name 上使用索引,而第二个(针对列值的函数)没有。
  • @MarcusAdams 是正确的。当使用任何函数如LEFT、SUBSTRING等时,服务器不能使用索引。
  • 谢谢。不知道。

标签: tsql comparison sql-like


【解决方案1】:

Entity Framework Core 用户

您可以使用EF.Functions.Like(columnName, searchString + "%") 而不是columnName.startsWith(...),您将在生成的SQL 中获得一个LIKE 函数,而不是所有这些“左”的疯狂!

根据您的需要,您可能需要预处理 searchString。

另见https://github.com/aspnet/EntityFrameworkCore/issues/7429

实体框架(非核心)EntityFunctions 中不存在此功能,因此我不确定如何为 EF6 执行此功能。

【讨论】:

    【解决方案2】:

    当搜索列包含索引时,我总是建议使用 like 运算符。我在生产环境中使用 select count(column_name) from table_name where left(column_name,3)='AAA' OR left(column_name,3)= 'ABA' OR ... 最多 9 个 OR 子句测试了上述查询。我的计数显示 7301477 条记录,左侧 4 秒,左侧 1 秒,例如 where column_name like 'AAA%' OR Column_Name like 'ABA%' or ... 最多 9 个类似子句。

    在 where 子句中调用函数不是最佳实践。参考http://blog.sqlauthority.com/2013/03/12/sql-server-avoid-using-function-in-where-clause-scan-to-seek/

    【讨论】:

      【解决方案3】:

      “Left”与“Like”——在实现索引的情况下,应始终使用“Like”,因为“Like”不是函数,因此可以利用您可能拥有的任何索引数据。

      另一方面,“Left”是函数,因此不能使用索引。 This web page 用一些例子描述了使用差异。这意味着 SQL 服务器必须为返回的每条记录评估函数。

      “子字符串”和其他类似的函数也是罪魁祸首。

      【讨论】:

      • 虽然我理解并同意,但我认为 MySQL 代码库应该足够智能,可以将简单的 LEFT() 调用转换为 LIKE 语句,或者利用 LEFT() 的第一个操作数上的索引。就像 OP 一样,我只是偶然发现 LEFT() 在我的代码中运行缓慢,并且惊讶地发现它没有经过优化以与 LIKE 在性能上相似。
      【解决方案4】:

      我有一个类似的问题,并且对两者都进行了测试。这是我的代码。

      where (VOUCHER like 'PCNSF%'
          or voucher like 'PCLTF%'
          or VOUCHER like 'PCACH%'
          or VOUCHER like 'PCWP%'
          or voucher like 'PCINT%')
      

      在 1 分 51 秒内返回 1434 行。

      where (LEFT(VOUCHER,5) = 'PCNSF'
          or LEFT(VOUCHER,5)='PCLTF'
          or LEFT(VOUCHER,5) = 'PCACH'
          or LEFT(VOUCHER,4)='PCWP'
          or LEFT (VOUCHER,5) ='PCINT')
      

      在 1 分 27 秒内返回 1434 行

      左侧 5 的数据更快。顺便说一句,我的整体查询确实命中了一些索引。

      【讨论】:

      【解决方案5】:

      最好的办法是根据实际生产数据衡量性能,而不是试图猜测(或询问我们)。这是因为性能有时可能取决于您正在处理的数据,尽管在这种情况下似乎不太可能(但我不知道,因此您应该检查)。

      如果这是一个您会做很多事情的查询,您应该考虑另一个(索引)列,其中包含name 的小写首字母,并由插入/更新触发器设置。

      这将以最小的存储空间增加为代价,使该查询异常快速:

      select * from table where name_first_char_lower = @firstletter
      

      这是因为大多数数据库的读取频率远高于写入频率,这将在所有读取中分摊计算成本(仅针对写入进行)。

      它引入了冗余数据,但只要您了解(并按照此建议减轻)后果并需要额外性能,就可以这样做以提高性能。

      【讨论】:

      • 这是一个非常好的主意,尽管该表中的数据仅在不到 5% 的读取中以这种方式读取。所有其他人都将被过滤掉其他没有名字的东西......所以索引似乎不可行。
      • name列上的索引可以用于name like 'a%',不需要计算列。
      • Andomar,好点子 - 虽然我知道一些 DBMS' 允许在列上计算索引(因此它会自动小写),但它不会处理不区分大小写的性质。跨度>
      • 是否区分大小写取决于 SQL Server 中的列排序规则。该问题被标记为 TSQL。
      猜你喜欢
      • 2011-12-24
      • 1970-01-01
      • 1970-01-01
      • 2010-10-03
      • 2011-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多