Es gab kürzlich eine Debatte auf der effizientesten Art und Weise, eine MS SQL-Datenbank mit LIKE
und Platzhaltern zu durchsuchen. Wir vergleichen mit %abc%
, %abc
und abc%
. Eine Person hat gesagt, dass Sie immer die Wildcard am Ende der Laufzeit haben sollten (abc%
). Also, nach ihnen, wenn wir etwas finden wollten, das mit "abc" endete, wäre es am effizientesten, "reverse (column) LIKE reverse ('% abc') zu verwenden.SQL Wildcard-Suche - Effizienz?
Ich habe einen Test mit SQL Server 2008 (R2) bis jede der folgenden Aussagen vergleichen:
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 hält rund 500.000 Datensätze gibt es über 7.400 Adressen, die „Straße“, und über beenden 8.500 Adressen, die "Street" haben, aber nicht unbedingt am Ende. Jeder Testlauf dauerte 2 Sekunden und sie alle die gleiche Anzahl von Zeilen außer %STREET%
zurückgegeben, die eine zusätzliche 900 oder so Ergebnisse gefunden, weil es Adressen, die eine Wohnung Nummer am Ende hatte.
Da der SQL Server-Test keinen Unterschied in der Ausführungszeit zeigen, habe ich in PHP bewegt, wo ich den folgenden Code verwendet wird, in jeder Anweisung Umschalten schnell mehrere Tests ausführen:
<?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>";
?>
Die Ergebnisse der Dieser Test war ungefähr so zweideutig wie die Ergebnisse beim Testen in SQL Server.
%STREET
in 166.5823 Sekunden abgeschlossen (.3331 Durchschnitt pro Abfrage), und gemittelt 500 Ergebnisse in .0228 gefunden.
%STREET%
in 149,4500 Sekunden abgeschlossen (Durchschnitt von .2989 pro Abfrage) und gemittelt 500 Ergebnisse in .0177 gefunden. (Schnellere Zeit pro Ergebnis, da in derselben Zeit mehr Ergebnisse gefunden werden als in den anderen.)
reverse(ADDRESS) like reverse('%STREET')
in 134,0115 Sekunden abgeschlossen (Durchschnitt von .2680 pro Abfrage) und gemittelt 500 Ergebnisse in .0183 Sekunden gefunden.
reverse('TREETS%')
in 167,6960 Sekunden abgeschlossen (0,3354 Durchschnitt pro Abfrage), und gemittelt 500 Ergebnisse in .0229 gefunden.
Wir erwarteten, dass dieser Test zeigen würde, dass %STREET%
am langsamsten wäre, während es tatsächlich am schnellsten lief und die beste durchschnittliche Zeit hatte, um 500 Ergebnisse zu liefern. Während der vorgeschlagene reverse('%STREET')
war am schnellsten, insgesamt zu laufen, war aber etwas langsamer in der Zeit, um 500 Ergebnisse zurückzugeben.
Zusätzlicher Spaß: Ein Mitarbeiter hat Profiler auf dem Server ausgeführt, während wir die Tests ausgeführt haben und festgestellt, dass die Verwendung des doppelten Platzhalters eine signifikante Erhöhung der CPU-Auslastung zur Folge hatte, während die anderen Tests innerhalb von 1-2% lagen.
Gibt es irgendwelche SQL Efficiency-Experten, die erklären können, warum der Platzhalter am Ende des Suchstrings besser geeignet ist als der Anfang, und vielleicht warum die Suche mit Platzhaltern am Anfang und Ende des Strings schneller war als die Wildcard nur am Anfang zu haben?
'ABC' haben Did Sie löschen die Puffer und Cache vor jedem Test? –
Ja, bevor jede Abfrage getestet wurde, starteten wir den Server neu, um sicherzustellen, dass es ein fairer Test war. – Jeremy1026
Der reverse() - Ansatz wird einen Tabellenscan erzwingen, da jede Zeile umgekehrt werden muss. Normalerweise wird sie mit Präfix-Platzhalter + einer vorberechneten umgekehrten Spalte verwendet. –