15

LIKE最近,关于使用和通配符搜索 MS SQL 数据库的最有效方法一直在争论。我们使用%abc%%abc和进行比较abc%。有人说过,您应该始终在术语末尾使用通配符 ( abc%)。因此,根据他们的说法,如果我们想找到以“abc”结尾的东西,使用 `reverse(column) LIKE reverse('%abc') 是最有效的。

我使用 SQL Server 2008 (R2) 设置了一个测试来比较以下每个语句:

select * from CLMASTER where ADDRESS like '%STREET'
select * from CLMASTER where ADDRESS like '%STREET%'   
select * from CLMASTER where ADDRESS like reverse('TEERTS%')  
select * from CLMASTER where reverse(ADDRESS) like reverse('%STREET')

CLMASTER 拥有大约 500,000 条记录,大约有 7,400 个地址以“Street”结尾,大约 8,500 个地址中有“Street”,但不一定在结尾。每次测试运行需要 2 秒,它们都返回了相同数量的行,除了%STREET%,它发现了额外的 900 左右的结果,因为它选择了最后有公寓号码的地址。

由于 SQL Server 测试在执行时间上没有显示出任何差异,我转而使用 PHP,在其中使用以下代码,在每个语句中切换,以快速运行多个测试:

<?php

    require_once("config.php");
    $connection = odbc_connect( $connection_string, $U, $P );

    for ($i = 0; $i < 500; $i++) {
    $m_time = explode(" ",microtime());
    $m_time = $m_time[0] + $m_time[1];

    $starttime = $m_time;

    $Message=odbc_exec($connection,"select * from CLMASTER where ADDRESS like '%STREET%'");
    $Message=odbc_result($Message,1);

    $m_time = explode(" ",microtime());
    $m_time = $m_time[0] + $m_time[1];

    $endtime = $m_time;

    $totaltime[] = ($endtime - $starttime);

}

odbc_close($connection);

echo "<b>Test took and average of:</b> ".round(array_sum($totaltime)/count($totaltime),8)." seconds per run.<br>";
echo "<b>Test took a total of:</b> ".round(array_sum($totaltime),8)." seconds to run.<br>";

?>

此测试的结果与在 SQL Server 中进行测试时的结果一样模棱两可。

%STREET在 166.5823 秒内完成(每个查询平均 0.3331),平均 0.0228 中找到 500 个结果。

%STREET%在 149.4500 秒内完成(每个查询平均 0.2989),平均 0.0177 找到 500 个结果。(每个结果的时间更快,因为它在相似的时间内找到比其他结果更多的结果。)

reverse(ADDRESS) like reverse('%STREET')在 134.0115 秒内完成(每个查询平均 0.2680),平均在 0.0183 秒内找到 500 个结果。

reverse('TREETS%')在 167.6960 秒内完成(每个查询平均 0.3354),平均 0.0229 找到 500 个结果。

我们预计此测试将显示%STREET%总体上最慢的,而实际上它是运行速度最快的,并且返回 500 个结果的平均时间最好。虽然建议reverse('%STREET')的整体运行速度最快,但返回 500 个结果的时间稍慢。

额外的乐趣:当我们运行测试时,一位同事在服务器上运行分析器,发现使用双通配符会显着增加 CPU 使用率,而其他测试之间的差异在 1-2% 以内。

是否有任何 SQL 效率专家可以解释为什么在搜索字符串的末尾使用通配符比在开头更好的做法,以及为什么在字符串的开头和结尾使用通配符搜索比使用通配符更快刚开始?

4

4 回答 4

24

如果该列被索引,则在字符串末尾使用通配符'abc%'会有所帮助,因为它将能够直接查找以开头的记录并忽略其他所有内容。开头有通配符意味着它必须查看每一行,而不考虑索引。'abc'

好文章在这里有更多解释。

于 2012-08-03T12:35:02.397 回答
3

Like只有字符串末尾的通配符才会使用索引。

Contains如果您想提高字符串前后通配符的速度,您应该考虑使用 FTS 。另请参阅有关 Contains 与 Like 的相关 SO 帖子

于 2012-08-03T12:37:23.230 回答
2

Microsoft来看,保留结束通配符更有效,因为如果存在通配符,它​​可以使用索引而不是执行扫描。想想搜索是如何工作的,如果您不知道它之前是什么,那么您必须扫描所有内容,但如果您只搜索尾部,那么您可以对行进行排序,甚至可能(取决于您要查找的内容) ) 进行准二分搜索。

连接或谓词中的一些运算符往往会产生资源密集型操作。具有用通配符(“%a value%”)括起来的值的 LIKE 运算符几乎总是会导致表扫描。由于前面的通配符,这种类型的表扫描是一项非常昂贵的操作。只有关闭通配符的 LIKE 运算符可以使用索引,因为索引是 B+ 树的一部分,并且通过从左到右匹配字符串值来遍历索引。

因此,上面的引用也解释了为什么在运行两个通配符时会出现巨大的处理器峰值。它只是偶然地完成得更快,因为有足够的马力来掩盖效率低下。在尝试确定查询的性能时,您希望查看查询的执行而不是服务器的资源,因为这些可能会产生误导。如果我的服务器有足够的马力来满足天气的需求,并且我正在对小至 500,000 行的表运行查询,那么结果将具有误导性。

减去 Microsoft 引用您的答案的事实,在进行性能分析时,请考虑深入学习如何阅读执行计划。这是一项投资,而且非常枯燥,但从长远来看,这是值得的。

简而言之,无论谁指出仅使用尾随通配符更有效,都是正确的。

于 2012-08-03T12:35:41.157 回答
-6

在 MS SQL 中,如果您想获得以 'ABC' 结尾的名称,那么您可以进行如下查询(假设表名是student

select * from  student where student_name like'%[ABC]'

所以它会给那些以'A','B','C'结尾的名字。

2)如果你想拥有以'ABC'开头的名字意味着 -

select * from student where student_name like '[ABC]%'

3)如果你想有中间有'ABC'的名字

select * from student where student_name like '%[ABC]%' 
于 2013-02-25T04:31:05.210 回答