繁体   English   中英

SQL通配符搜索 - 效率?

[英]SQL Wildcard Search - Efficiency?

最近在使用LIKE和通配符搜索MS SQL数据库的最有效方法上进行了辩论。 我们使用%abc%%abcabc% 一个人说你应该在学期结束时( 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秒内完成(每个查询平均值为.3331),在.0228中找到平均500个结果。

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

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

reverse('TREETS%')在167.6960秒内完成(每个查询平均为.3354),平均在.0229中找到500个结果。

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

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

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

在字符串的末尾加上通配符,比如'abc%'如果该列被索引,将会有所帮助,因为它可以直接查找以'abc'开头的记录并忽略其他所有内容。 在开头使用外卡意味着它必须查看每一行,无论索引如何。

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

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

如果要提高字符串前面和后面的通配符速度,应该查看使用FTS Contains 请参阅有关Contains vs. Like的相关SO帖子

Microsoft离开结束通配符更有效,因为它可以(如果存在)使用索引而不是执行扫描。 想想搜索可能如何工作,如果你不知道它之前是什么,那么你必须扫描所有内容,但是如果你只搜索尾部那么你可以订购行甚至可能(取决于你要找的东西) )进行准二分搜索。

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

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

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

简而言之,无论谁表明尾随通配符只是更有效,都是正确的。

在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]%' 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM