Der einzige Weg, den ich mir vorstellen kann, um diese Art von Unterschied in der Ausführungsgeschwindigkeit zu erreichen, wäre (a) einen Index für field4
zu haben , und (b) haben eine Vielzahl von leeren Datenblöcken; möglicherweise von einer hohen Wassermarke, die durch wiederholte Direct-Path-Lasten sehr hoch gesetzt wurde.
Die erste Abfrage würde weiterhin den Index verwenden und wie erwartet ausgeführt werden. Da Nullwerte jedoch nicht indiziert werden, kann der Index nicht verwendet werden, um zu prüfen, ob or field4 is null
Bedingung, sodass es auf einen vollständigen Tabellenscan zurückgreifen würde.
Das an sich sollte hier kein Problem darstellen, da ein vollständiger Tabellenscan von 7000 Zeilen nicht lange dauern sollte. Aber da es ist Es dauert so lange, da passiert etwas anderes. Ein vollständiger Tabellenscan muss jeden der Tabelle zugewiesenen Datenblock untersuchen, um festzustellen, ob er Zeilen enthält, und die Zeit, die dafür benötigt wird, deutet darauf hin, dass es viel mehr Blöcke gibt, als Sie benötigen, um 7000 Zeilen zu speichern, selbst mit Inline-CLOB-Speicher.
Der einfachste Weg, viele leere Datenblöcke zu erhalten, besteht darin, viele Daten zu haben und dann die meisten 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/*+ append */
haben Hinweis; oder parallel; oder über SQL*Loader. Jedes Mal, wenn Sie dies taten, verschob sich die Hochwassermarke, da alte leere Blöcke nicht wiederverwendet wurden; und jedes Mal würde sich die Leistung der Abfrage, die auf Nullen prüft, ein wenig verschlechtern. Nach vielen Iterationen würde sich das wirklich summieren.
Sie können im Datenwörterbuch nachsehen, wie viel Platz Ihrer Tabelle zugewiesen ist (user_segments
usw.), und vergleichen Sie das mit der Größe der Daten, die Sie glauben, tatsächlich zu haben. Sie können das HWM zurücksetzen, indem Sie die Tabelle neu aufbauen, z. B. indem Sie Folgendes tun:
alter table mytable move;
(am besten in einem Wartungsfenster!)
Als Demo habe ich einen Zyklus zum direkten Einfügen und Löschen von 7000 Zeilen über hundert Mal ausgeführt und dann Ihre beiden Abfragen ausgeführt. Der erste dauerte 0,06 Sekunden (wobei ein Großteil davon SQL Devleoper-Overhead ist); die zweite nahm 1.260. (Ich habe auch Gordon's geleitet, das eine ähnliche Zeit hatte, da es noch ein FTS machen muss). Mit mehr Iterationen würde der Unterschied noch deutlicher werden, aber mir ging der Platz aus ... Ich habe dann eine alter table move
durchgeführt und Ihre zweite Abfrage erneut ausgeführt, was dann 0,05 Sekunden gedauert hat.