SQL通配符搜索-效率?

SQL通配符搜索-效率?,sql,sql-server,sql-server-2008,query-optimization,processing-efficiency,Sql,Sql Server,Sql Server 2008,Query Optimization,Processing Efficiency,最近,关于使用LIKE和通配符搜索MS SQL数据库的最有效方法,人们展开了一场争论。我们正在使用%abc%、%abc和abc%进行比较。有人说你应该在学期结束时使用通配符(abc%)。因此,根据他们的说法,如果我们想找到以“abc”结尾的东西,最好使用像reverse('%abc')这样的`reverse(column') 我使用SQL Server 2008(R2)设置了一个测试,以比较以下语句: select * from CLMASTER where ADDRESS like '%STR

最近,关于使用
LIKE
和通配符搜索MS SQL数据库的最有效方法,人们展开了一场争论。我们正在使用
%abc%
%abc
abc%
进行比较。有人说你应该在学期结束时使用通配符(
abc%
)。因此,根据他们的说法,如果我们想找到以“abc”结尾的东西,最好使用像reverse('%abc')这样的`reverse(column')

我使用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拥有大约500000条记录,大约有7400个地址位于“Street”结尾,大约8500个地址位于“Street”结尾,但不一定位于“Street”结尾。每次测试运行耗时2秒,它们都返回相同数量的行,除了
%STREET%
,因为它提取了末尾有公寓号的地址,所以额外发现了900个左右的结果

由于SQL Server测试在执行时间上没有显示任何差异,因此我转入PHP,在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>";

?>

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

有更多解释的好文章。

从it中可以更有效地保留结束通配符,因为如果存在通配符,它可以使用索引而不是执行扫描。想一想搜索是如何工作的,如果你不知道在它之前是什么,那么你必须扫描所有东西,但是如果你只搜索尾部,那么你可以对行进行排序,甚至可能(取决于你在寻找什么)进行准二进制搜索

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

因此,上面的引文也解释了为什么在运行两个通配符时会出现巨大的处理器峰值。因为有足够的马力来掩盖效率低下的问题,所以它只能通过偶然事件来更快地完成。当试图确定查询的性能时,您希望查看查询的执行情况,而不是服务器的资源,因为这些可能会产生误导。如果我有一台足够马力的服务器来为天气预报服务,并且我在小到500000行的表上运行查询,那么结果就会产生误导

当微软引用你的答案时,当你做性能分析时,考虑跳水到学习如何阅读执行计划。这是一项投资,而且非常枯燥,但从长远来看是值得的


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

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


如果要提高字符串前后通配符的速度,应该考虑使用FTS。另外。

在MS SQL中,如果您想获得以“ABC”结尾的名称,则可以使用如下查询(假设表名为
student

因此,它将给出以“A”、“B”、“C”结尾的名称

2) 如果你想让名字以ABC开头意味着-

select * from student where student_name like '[ABC]%'
3) 如果你想要中间有“ABC”的名字

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

在每次测试之前是否清除了缓冲区和缓存?是的,在测试每个查询之前,我们重新启动了服务器以确保它是一个公平的测试。reverse()方法将强制执行表扫描,因为每一行都必须反转,它通常与前缀通配符+预先计算的反向列一起使用。索引可以减少I/O,即使模式以通配符开头,因为不需要扫描表行。覆盖索引还可以提高性能。从广义上讲,这意味着像“abc%”这样的
反向(col)操作是个坏主意。是的,
反向
或任何其他改变索引列的计算都意味着你失去了搜索能力。谢谢你的回答/评论provided@AdamRobinson不倒也不是个坏主意,我也使用它,只需将反转的值存储在新的column@Jeremy1026-我更新了我的答案,对服务器性能使用的结果做了更多的澄清。感谢您提供的答案。感谢您提供的答案,不幸的是,对于我们来说,切换到Contains并不是一个可行的解决方案,因为我们需要对相当多的(数百个)表进行全文索引才能使其成为一个可行的解决方案。我们经常搜索特定的子字符串和其他项。
select * from student where student_name like '%[ABC]%'