Frage

Ich frage mich, was die Leistung einer Abfrage wie mit dem Schlüsselwort LIKE und den Platzhalter als der Wert im Vergleich zu mit keiner where-Klausel überhaupt wäre.

Betrachten wir eine where-Klausel wie "wo ein LIKE '%'". Dadurch werden alle möglichen Werte der Spalte ‚a‘ entsprechen. Wie vergleicht dies die where-Klausel nicht mit überhaupt.

Der Grund, warum ich diese frage ist, dass ich eine Anwendung, wo einige Felder gibt, die der Benutzer Werte angeben können auf suchen. In einigen Fällen möchte der Benutzer alle möglichen Ergebnisse. Ich bin derzeit eine einzelne Abfrage wie folgt aus:

SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?

Die Werte von ‚%‘ und ‚%‘ können alle möglichen Werte entsprechen für a und b oder geliefert werden. Dies ist praktisch, da ich eine einzelne benannte Abfrage in meiner Anwendung für diese verwenden kann. Ich frage mich, was die Leistung Überlegungen dafür sind. Ist die Abfrage-Optimierer LIKE ‚%‘ reduzieren, um einfach alle Vorstellungen? Ich weiß, dass, weil ich eine benannte Abfrage (vorbereitete Anweisung) verwendet wird, dass auch die Antwort beeinflussen kann. Ich weiß, die Antwort wahrscheinlich Datenbank spezifisch ist. So speziell wie würde diese Arbeit in Oracle, MS SQL Server und Derby.

Der alternative Ansatz dazu wäre die Verwendung 3 separate Abfragen basierend auf dem Benutzer die Wildcard eingegeben werden.

A ist Wildcard-Abfrage:

SELECT * FROM TableName WHERE b LIKE ?

B ist Wildcard-Abfrage:

SELECT * FROM TableName WHERE a LIKE ?

A und B sind Platzhalter:

SELECT * FROM TableName

Keine Platzhalter:

SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?

Offensichtlich eine einzelne Abfrage, die die einfachste und am leichtesten zu halten. Ich würde lieber nur die eine Abfrage verwenden, wenn die Leistung noch gut sein.

War es hilfreich?

Lösung 3

Ich hatte gehofft, es würde ein Lehrbuch Antwort auf diese Frage, aber es klingt wie es weitgehend mit unterschiedlichen Datenbanktypen variieren. Die meisten Antworten darauf hingewiesen, dass ich einen Test laufen sollte, so dass genau das, was ich getan habe.

Meine Anwendung in erster Linie zielt auf die Derby, MS SQL und Oracle-Datenbanken. Da Derby laufen eingebettet werden kann und ist einfach einzurichten, testete ich die Leistung an diesem ersten. Die Ergebnisse waren überraschend. Getestet habe ich das Worst-Case-Szenario gegen einen ziemlich großen Tisch. Ich lief den Test 1000 mal und gemittelt, um die Ergebnisse.

Abfrage 1:

SELECT * FROM TableName

Abfrage 2 (mit Werten von a = "%" und b = "%"):

SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?

Abfrage 1 durchschnittliche Zeit: 178ms

Abfrage 2 durchschnittliche Zeit: 181ms

So Leistung auf Derby ist fast gleich zwischen den beiden Abfragen.

Andere Tipps

SQL Server wird in der Regel finden Sie unter

WHERE City LIKE 'A%'

und behandelt es als

WHERE City >= 'A' AND City < 'B'

... und glücklich ein Index suchen verwenden, wenn angemessen. Ich sage ‚im Allgemeinen‘, weil ich es diese Vereinfachung in bestimmten Fällen zu tun gesehen habe scheitern.

Wenn jemand zu tun versucht:

WHERE City LIKE '%ville'

... dann versuchen, ein Index im Wesentlichen unmöglich sein wird.

Aber etwas so einfach wie:

WHERE City LIKE '%'

wird entsprechend berücksichtigt werden:

WHERE City IS NOT NULL

Sie können unabhängig von Query-Analyse des DBMS Angebots (zB EXPLAIN für MySQL, SET SHOWPLAN_ALL ON für MS SQL (oder verwenden eine der andere Methoden ), EXPLAIN PLAN FOR für Oracle ), um zu sehen, wie die Abfrage ausgeführt wird.

Jede DBMS wert sein Salz würde LIKE '%' Klauseln abzustreifen, bevor auch nur zu versuchen, die Abfrage auszuführen. Ich bin ziemlich sicher, ich habe DB2 / z in seinen Ausführungsplänen tun gesehen.

Die vorbereitete Anweisung sollte keinen Unterschied machen, da es in gedreht werden sollte real SQL bevor es wird auf die Ausführungs-Engine.

Aber wie bei allen Optimierungsfragen, Maßnahme nicht erraten ! DBAs existieren, weil sie stimmen ständig das DBMS auf aktuellen Daten basiert (das ändert sich im Laufe der Zeit). Als absolutes Minimum sollten Sie Zeit (und die Ausführungspläne zu erhalten) für alle Varianten mit geeigneten statischen Daten, um zu sehen, ob es ein Unterschied.

Ich weiß, dass Anfragen wie:

select c from t where ((1 = 1) or (c = ?))

ist optimiert die gesamten where-Klausel vor der Ausführung zu entfernen (auf DB2 sowieso und, bevor Sie fragen, das Konstrukt ist nützlich, wenn man die Wirkung der Where-Klausel entfernen, muß aber noch die Parameter beibehalten Platzhalter (BIRT mit Javascript mit den Anfragen für Wildcards ändern)).

Derby bietet auch Werkzeuge für den aktuellen Abfrage-Plan untersucht, die verwendet wurde, so dass man Experimente mit Derby laufen und sehen Sie den Abfrage-Plan, das Derby wählte. Sie können Derby mit -Dderby.language.logQueryPlan = true ausführen, und Derby der Abfrage-Plan schreiben derby.log, oder Sie können die RUNTIMESTATISTICS Anlage verwenden, wie hier beschrieben: http://db.apache.org/derby/docs/10.5/tuning/ctundepth853133.html

Ich bin mir nicht sicher, ob Derby wird die A LIKE ‚%‘ Streifen aus der Zeit voraus, aber ich glaube auch nicht, dass das Vorhandensein dieser Klausel viel von einer Verlangsamung der Ausführungsgeschwindigkeit einführen wird.

Ich würde sehr interessiert sein, die eigentlichen Abfrage-Plan ausgegeben, um zu sehen, die Sie in Ihrer Umgebung erhalten, mit und ohne die A LIKE ‚%‘ Klausel statt.

Oracle 10gR2 scheint keine spezielle Optimierung für diese Situation durchzuführen, aber es erkennt, dass LIKE ‚%‘ schließt nulls.

create table like_test (col1)
as select cast(dbms_random.string('U',10) as varchar2(10))
from dual
connect by level <= 1000
/
insert into like_test values (null)
/
commit
/

exec dbms_stats.gather_table_stats(user,'like_test')

explain plan for
select count(*)
from   like_test
/
select plan_table_output from table(dbms_xplan.display)
/
explain plan for
select count(*)
from   like_test
where  col1 like '%'
/
select plan_table_output from table(dbms_xplan.display)
/
explain plan for
select count(*)
from   like_test
where  col1 is not null
/
select plan_table_output from table(dbms_xplan.display)
/

... geben ...

Plan hash value: 3733279756

------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Cost (%CPU)| Time     |
------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |            |          |
|   2 |   TABLE ACCESS FULL| LIKE_TEST |  1001 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------

... und ...

Plan hash value: 3733279756

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |    10 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |    10 |            |          |
|*  2 |   TABLE ACCESS FULL| LIKE_TEST |  1000 | 10000 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("COL1" LIKE '%')

... und ...

Plan hash value: 3733279756

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |    10 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |    10 |            |          |
|*  2 |   TABLE ACCESS FULL| LIKE_TEST |  1000 | 10000 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("COL1" IS NOT NULL)

Beachten Sie die Mächtigkeit (Zeilen) auf der TABLE ACCESS FULL Zeile

Je nachdem, wie das LIKE-Prädikat ist strukturiert und auf dem Feld sind die Prüfung auf Sie, Sie könnten einen vollständigen Tabellenscan benötigen. Semantisch ein ‚%‘ könnte eine vollständige Tabelle Scan implizieren aber SQL Server ist, alle Arten von Optimierung intern auf Abfragen. Die Frage lautet also: Ist SQL Server auf einem LIKE-Prädikat optimiert mit ‚%‘ gebildet und wirft sie aus der WHERE-Klausel

Ein Aspekt, den ich denke, ist aus der Diskussion fehlt, ist die Tatsache, dass die OP will eine vorbereitete Erklärung verwenden. Zu der Zeit, die Anweisung vorbereitet wird, wird die Datenbank / Optimierer nicht in der Lage sein, die Vereinfachungen andere zu arbeiten, erwähnt haben und so nicht in der Lage sein, die a like '%' zu optimieren weg als der tatsächliche Wert wird überhaupt nicht vorbereitet Zeit bekannt sein.

Deshalb:

  • wenn Prepared Statements, hat vier verschiedene Aussagen verfügbar (0, nur, nur b, beide) und verwenden Sie den entsprechend man bei Bedarf
  • sehen, wenn Sie eine bessere Leistung erhalten, wenn Sie nicht über eine vorbereitete Anweisung verwenden, wenn nur eine Anweisung kleben (obwohl dann wäre es ziemlich einfach sein, nicht ‚leer‘ Bedingungen enthalten)

Was passiert, wenn eine Spalte einen Nicht-Null-Leerwert hat? Ihre Anfrage wird es wohl entsprechen.

Wenn dies eine Abfrage für eine reale Anwendung ist dann versuchen, die freie Textindizierung Funktionen der meisten moderner SQL-Datenbanken. Die Performance-Probleme werden sich nicht signifikant.

Eine einfache if-Anweisung von wenn (A B)  Suche nach einem b sonst (A)  Suche ein sonst B  Suche b sonst  sagen Benutzer sie nichts angeben

ist trivial zu halten und wird viel einfacher zu verstehen, anstatt Annahmen über den LIKE-Operator zu machen. Sie gehen zu tun wahrscheinlich, dass auf jeden Fall in der Benutzeroberfläche, wenn Sie die Ergebnisse anzeigen „Ihre Suche nach A gefunden x“ oder „Ihre Suche nach einem B gefunden ...“

Ich bin mir nicht sicher, ob der Wert eine vorbereitete Anweisung mit der Art von Parametern Sie beschreiben. Der Grund dafür ist, dass Sie die Abfrage-Optimierer in der Vorbereitung einen Ausführungsplan täuschen könnte, die völlig falsch, je nachdem, welche der Parameter wurden ‚%‘.

sein würde

Zum Beispiel, wenn die Anweisung mit einem Ausführungsplan vorbereitet wurden, den Index auf Spalte A, aber der Parameter für die Spalte A stellte sich heraus, ‚%‘ sein, dass Sie eine schlechte Leistung.

ein where-Klausel mit „wie‚%‘“ als das einzige Prädikat verhält genau das gleiche wie keine where-Klausel überhaupt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top