簡體   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