15

LIKE最近、ワイルドカードを使用してMSSQLデータベースを検索する最も効率的な方法について議論が行われています。%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レコードを保持し、「Street」で終わる約7,400のアドレスと、「Street」が含まれるが必ずしも最後ではない約8,500のアドレスがあります。各テストの実行には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>";

?>

このテストの結果は、SQLServerでテストしたときの結果とほぼ同じくらいあいまいでした。

%STREET166.5823秒(クエリあたり平均.3331)で完了し、.0228で平均500件の結果が見つかりました。

%STREET%149.4500秒(クエリあたり平均.2989)で完了し、.0177で平均500件の結果が見つかりました。(同様の時間に他の結果よりも多くの結果が見つかるため、結果ごとの時間が短縮されます。)

reverse(ADDRESS) like reverse('%STREET')134.0115秒(クエリあたり平均.2680)で完了し、.0183秒で平均500件の結果が見つかりました。

reverse('TREETS%')167.6960秒(クエリあたり平均.3354)で完了し、.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 演算子は、ほとんどの場合、テーブル スキャンを引き起こします。このタイプのテーブル スキャンは、前にワイルドカードがあるため、非常にコストのかかる操作です。インデックスは B+ ツリーの一部であり、文字列値を左から右に照合することによってインデックスがトラバースされるため、終了ワイルドカードのみを使用する LIKE 演算子はインデックスを使用できます。

したがって、上記の引用は、 2 つのワイルドカードを実行したときにプロセッサが急増た理由も説明しています。非効率をカバーするのに十分な馬力があるため、たまたまより速く完了しました。クエリのパフォーマンスを判断しようとするときは、誤解を招く可能性があるため、サーバーのリソースではなく、クエリの実行を確認する必要があります。天気予報に対応するのに十分な馬力を備えたサーバーがあり、500,000 行ほどの小さなテーブルでクエリを実行している場合、結果は誤解を招く可能性があります。

マイクロソフトがあなたの答えを引用したという事実はさておき、パフォーマンス分析を行うときは、実行計画の読み方を学ぶことに飛び込むことを検討してください。それは投資であり、非常に乾燥していますが、長期的には価値があります.

要するに、末尾のワイルドカードのみがより効率的であることを示していた人は誰でも正しいです。

于 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 に答える