2016-07-29 10 views
1

Ich habe diese Tabelle 7.000 DatensätzeWarum verlangsamt die Suche nach null diese Abfrage?

ab ARADMIN.V_PKGXMLCODE

Name     Null  Type   
--------------------- -------- ------------- 
REQUEST_ID   NOT NULL VARCHAR2(15) 
AVAILABILITY     VARCHAR2(69) 
XML_CODE      CLOB   
PACKAGENAME_UNIQUE    VARCHAR2(50) 
CATALOG      NUMBER(15)  
CHILD       VARCHAR2(255) 
CLASSIFICATION_SYSTEM   NUMBER(15)  
E_MAIL       VARCHAR2(69) 

Die Abfrage

SELECT COUNT(*) FROM ARADMIN.V_PKGXMLCODE WHERE (CATALOG <> 0 AND CATALOG <> 2) AND (NOT (CHILD IS NULL)); 

dauert weniger als eine Sekunde enthält.

Die Abfrage

SELECT COUNT(*) FROM ARADMIN.V_PKGXMLCODE WHERE (CATALOG IS NULL OR (CATALOG <> 0 AND CATALOG <> 2)) AND (NOT (CHILD IS NULL)); 

dauert 23 Sekunden.

Erklären Plan jedoch behauptet, sollte es ganz schnell gehen ...

enter image description here

Was kann ich tun?

+0

Führt die erste Abfrage auch einen vollständigen Tabellenscan durch oder gibt es einen Index für field4, den sie verwenden kann? Und wenn das der Fall ist, wurde die Tabelle wiederholt gelöscht (nicht abgeschnitten) und mit direkten Pfadeinfügungen neu gefüllt (d. H. Mit dem Hinweis '/ * + append * /')? –

+1

Was ist mit Plan für die erste Abfrage? – nilsman

+0

Die Bedingung 'IS NULL' ignoriert den Index, da NULL-Werte nicht indiziert werden können. Nun, Sie könnten den Optimierer mit einem konstanten Wert zusammen mit der Spalte NULLABLE während der Indizierung austricksen. Aber um im Rahmen Ihrer Frage zu antworten, wird Ihre zweite Abfrage nach einem ** FULL TABLE SCAN ** gehen, es sei denn, Sie führen den Optimierer wie zuvor beschrieben aus. Ihre erste Abfrage könnte die Indizes nutzen und FTS vermeiden. 1. Bitte posten Sie auch den Plan für die erste Abfrage. 2. Sind die Statistiken aktuell? –

Antwort

0

Das ist interessant. Ich würde erwarten, dass die Abfrage die gleiche Leistung hat, weil Oracle einen guten Optimierer hat und nicht von der NULL verwechselt werden sollte.

Wie funktioniert diese Version?

select x1.cnt + x2.cnt + x3.cnt 
from (select count(*) as cnt 
     from MYTABLE 
     where field4 = 1 and child is not null 
    ) x1 cross join 
    (select count(*) as cnt 
     from MYTABLE 
     where field4 = 4 and child is not null 
    ) x2 cross join 
    (select count(*) as cnt 
     from MYTABLE 
     where field4 is null and child is not null 
    ) x3; 

Diese Version sollte auf MYTABLE(field4, child) Vorteil eines Index zu übernehmen können.

+0

was ist x1 x2 x3? Es sagt ORA-00904: "X3": ungültiger Bezeichner? – Thomas

+0

@Thomas - das sind die Tabellenaliase für die Inline-Ansichten; sie sollten 'x3.cnt' usw. sein. –

+0

ok, ich verstehe. Es dauerte 23 Sekunden. – Thomas

3

Die einzige Art, wie ich auf field4 einen Index (a) wäre haben diese Art von Unterschied in der Ausführungsgeschwindigkeit zu bekommen denken kann, und (b) einen viele von leeren Datenblöcken; möglicherweise von einer hohen Wassermarke, die durch wiederholte Direktweglasten sehr hoch eingestellt ist.

Die erste Abfrage würde immer noch den Index verwenden und wie erwartet ausführen. Da Nullwerte jedoch nicht indiziert sind, kann der Index nicht zur Überprüfung der or field4 is null-Bedingung verwendet werden, sodass er auf einen vollständigen Tabellenscan zurückfällt.

Das sollte an sich kein Problem sein, da ein vollständiger Tabellenscan von 7000 Zeilen nicht lange dauern sollte. Aber seit es so lange dauert, ist etwas anderes los. Ein vollständiger Tabellenscan muss jeden der Tabelle zugewiesenen Datenblock untersuchen, um zu sehen, ob sie Zeilen enthalten, und die dafür benötigte Zeit lässt darauf schließen, dass selbst bei Inline-CLOB-Speicher mehr Blöcke als 7000 Zeilen vorhanden sind.

Der einfachste Weg, um viele leere Datenblöcke zu bekommen, ist, eine Menge Daten zu haben und dann den größten Teil davon zu löschen. Aber ich glaube, Sie haben in einem jetzt gelöschten Kommentar zu einer früheren Frage gesagt, dass die Leistung früher in Ordnung war und sich verschlechtert hat. Das kann passieren, wenn Sie direct-path inserts tun, insbesondere wenn Sie Daten "löschen", indem Sie sie löschen und dann neue Daten im Direktpfad-Modus einfügen. Sie könnten das mit Inserts tun, die den /*+ append */ Hinweis haben; oder parallel; oder über SQL * Loader. Jedes Mal, wenn Sie das tun, würde sich die Hochwassermarke bewegen, da alte leere Blöcke nicht wiederverwendet werden würden; und jedes Mal würde sich die Leistung der Abfrage, die auf Nullen prüft, etwas verschlechtern. Nach vielen Iterationen würde das wirklich beginnen sich zu summieren.

Sie können das Datenwörterbuch überprüfen, um zu sehen, wie viel Platz Ihrer Tabelle zugewiesen ist (user_segments usw.), und vergleichen Sie das mit der Größe der Daten, die Sie tatsächlich denken. Sie können die HWM zurücksetzen, indem Sie die Tabelle neu erstellen, z.g by doing: (! vorzugsweise in einem Wartungsfenster)

alter table mytable move; 

Als Demo lief ich einen Zyklus Einsatz zu leiten Pfad und löschen 7000 Zeilen über hundertmal, und dann liefen beide Ihre Fragen . Der erste dauerte 0,06 Sekunden (viel davon ist SQL Devleoper Overhead); der zweite dauerte 1.260. (Ich fuhr auch Gordon, der eine ähnliche Zeit bekam, da es immer noch eine FTS zu tun hat). Mit mehr Iterationen würde der Unterschied noch stärker werden, aber ich hatte keinen Platz mehr ... Dann habe ich einen alter table move gemacht und die zweite Abfrage erneut ausgeführt, was dann 0,05 Sekunden dauerte.

+0

Sie schlagen also vor, die Tabelle ARADMIN.V_PCKXMLCODE move zu ändern; ? – Thomas

+0

Oder erstellen Sie es auf andere Weise neu - aber Sie sollten das wahrscheinlich nicht tun, während andere darauf zugreifen. Ich versuche, an eine Abfrage zu denken, die zeigen wird, dass dies definitiv das Problem zuerst ist, und ich habe mich nicht besser gefühlt, als auf 'user_segments' zu schauen - ein echter DBA könnte in eine Idee eingreifen. Sie müssen außerdem ermitteln, ob direkte Pfadlasten tatsächlich auftreten. Wenn ja, wird das Problem nur allmählich wiederkehren. Wie werden die Daten in der Tabelle beibehalten? Und von seinem Namen ... ist es eigentlich eine Aussicht? Nun ja, der Plan sagt, dass die aktuelle Tabelle T111 ist - also wie wird * das * beibehalten? –

+0

Ich ging weiter und führte die Abfrage auf dem Tisch, auf den die Ansicht zugreift. Genau die gleichen Ergebnisse. Versuchen herauszufinden, wie die Daten verwaltet werden. – Thomas

Verwandte Themen