Oracle weigert Index zu verwenden
-
21-09-2019 - |
Frage
Ich habe einen partitionierten Tabelle wie folgt:
create table demo (
ID NUMBER(22) not null,
TS TIMESTAMP not null,
KEY VARCHAR2(5) not null,
...lots more columns...
)
Die Partition ist auf der TS
Spalte (eine Partition pro Jahr).
Da ich viel über den Zeitstempel suchen, habe ich einen kombinierten Index:
create index demo.x1 on demo (ts, key);
Die Abfrage sieht wie folgt aus:
select *
from demo t
where t.TS = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS')
Ich habe auch versucht and t.KEY = '00101'
hinzufügen, aber das nicht hilft.
Aber EXPLAIN PLAN
sagt, dass TABLE ACCESS
und FULL
:
# Operation Options Object Mode Cost Bytes Cardinality
0 SELECT STATEMENT ALL_ROWS 583804 287145 2127
1 PARTITION RANGE ALL 583804 287145 2127
2 TABLE ACCESS FULL HEADER ANALYZED 583804 287145 2127
Keine Erwähnung des Index. Was könnte falsch sein?
[EDIT] Aus irgendeinem Grund Oracle vollständig die Kosten für den Betrieb falsch berechnet. Ich habe 112 Millionen Zeilen in dieser Tabelle. Die Kosten für einen vollständigen Scan einer einzigen Partition sollten 20 Millionen, nicht 600'000 sein. Deshalb ist es ignoriert auch Optimierungshinweise.
[EDIT 2] Während meiner Tests lief ich dieses rätselhafte Ergebnis über. Wenn ich laufen diese select
:
select tx_ts
from kt.header
where tx_ts = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS')
ich dieses EXPLAIN PLAN:
0 SELECT STATEMENT ALL_ROWS 152 15616 1952
1 PARTITION RANGE ALL 152 15616 1952
2 INDEX FAST FULL SCAN HEADERX2 ANALYZED 152 15616 1952
Also, wenn ich mich auf die indexierte Spalte beschränken, wie die Ergebnis den select
entscheidet Oracle den Index zu verwenden. Wenn ich alle Spalten bekommen wollen, muss ich für einen Full Table Scan warten. Was ist denn hier los?
[EDIT 2] es gefunden; siehe meine Antwort unten.
Lösung
Okay, es war ein Fehler meinerseits: Die Spalte den Typ DATE
hatte, nicht TIMESTAMP
. Da ich to_timestamp()
verwendet, sah Oracle keine Möglichkeit, den Index zu verwenden.
Andere Tipps
Ich bin nicht wirklich ein Experte für Partitionierung, aber ich denke, was hier geschehen ist, ist, dass Sie einen globalen Index erstellt haben - einen einzigen Index, dass Abdeckungen Reihen in allen Partitionen. Daher weist das Optimierungs zwischen zwei sich gegenseitig ausschließende Zugriffspfade wählen: (A) einen Indexbereich Scan oder (B) partition pruning. Ich glaube, die PARTITION RANGE Betrieb zeigt an, dass es B gewählt hat.
Die Aktualisierung der Statistik, wie andere vorgeschlagen haben, kann das Verhalten ändern. Wenn Sie den Index löschen und neu erstellen, Sie Statistiken zu verwerfen, die für den Index existiert hat.
Erstellen des Index als UNIQUE, wenn der Zeitstempel und Schlüssel eine Zeile eindeutig identifizieren, wäre eine gute Idee sein, und könnte das Verhalten auch ändern.
Aber ich denke, die wirklichen „fix“ ist, dass Sie stattdessen lokalen Indizes erstellen sollte - einen separaten Index auf jeder Partition. Dies sollte den Optimierer aktivieren, indem Sie einen Index-Lookup gefolgt Partition Pruning zu tun. Ehrlich gesagt, ich bin nicht sicher, was die genaue Syntax, dies zu tun ist. Vielleicht erstellen Sie einfach den Index auf jeder Partition explizit die einzelnen Partitionsnamen.
Wenn alles andere fehlschlägt, könnte man einen Optimierungshinweis versuchen:
select /*+ index(demo.demo demo.x1) */ *
from demo t
where t.TS = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS')
Sind Ihre Statistiken auf dem neuesten Stand? Ungültige Statistiken kann, dass Oracle bedeuten glaubt, ein Full-Table-Scan ist schneller als der Index. Verwenden Sie keine Hinweise in Ihrer Abfrage, die Oracle könnte sagen, einen Scan zu tun?
Können Sie uns mit der vollständigen Abfrage liefern und Plan Ergebnisse erklären?
Edit: Aaron, können Sie die Statistiken aktualisieren "dbms_stats.gather_schema_stats" oder "dbms_stats.gather_table_stats" Kommandos. Siehe hier Weitere Informationen zu den Befehlen. Dies wird aktualisiert, alle relevanten Statistiken für das Schema oder Tabelle angegeben. Oracle Cost Based Optimizer werden die Statistiken verwenden, um die Ausführungsplan zu bestimmen zu wählen. Es verwendet nicht die tatsächlichen Tabellengrößen. Sie müssen Ihre Statistiken erneut zu aktualisieren, wenn die Größe der Tabelle deutlich verändert (+/- 10% oder so)
Eine andere Sache. Wenn Sie eine Verbindung Index verwenden, müssen Sie im Index in der Abfrage für den Optimierer verwendet, um alle der Spalten angeben, um den Index zu betrachten (und ich denke, Sie sie in der gleichen Reihenfolge wie auch angeben müssen, wenn ich falsch sein könnte dass, es ist ein gewesen Weile, da ich an diesem Zeug)
sahEs kann nur ein Tippfehler in der Transkription der „CREATE INDEX ...“ sein Aussage, dass Sie auf dem Laufenden, aber sind Sie sicher, dass Sie tatsächlich den Index erstellt?
Um uns einig First-Pass-Idee der Statistiken, diese Abfragen verwenden:
select table_name, num_rows
from user_tables
where table_name = 'DEMO';
select table_name, num_rows
from user_tab_partitions
where table_name = 'DEMO';
select index_name, num_rows from user_indexes
where table_name in
(select table_name
from user_tables where table_name = 'DEMO');
Auch genau wie generieren Sie den Plan erklären? Haben Sie Zugriff auf die Datenbank-Host eine Trace-Datei abrufen, wenn Sie Ablaufverfolgung aktivieren?
[Bearbeiten] Da bemerkte ich, wäre es gut, die Spur einer tatsächlichen Ausführung der Abfrage zu sehen. Da Sie Sie Zugriff auf die DB-Host-Dateisysteme haben angegeben haben, einen SQL-Skript ausgeführt, dass (in der gleichen Sitzung) gibt die folgenden:
alter session set sql_trace=true;
select /* THIS IS THE TRACE */
*
from demo t
where t.TS = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS');
exit
-
Nachdem das Skript beendet wird, finden Sie heraus, wo das Trace-Datei-Verzeichnis ist durch diese Abfrage:
Auswahlwert von v $ parameter where name = 'user_dump_dest';
-
Verwenden Sie, was Suchwerkzeug Ihnen zur Verfügung um die Datei zu finden das schließt die Zeichenfolge „DIES IST DER TRACE "
-
Prozess / Profil der Trace-Datei Ausgeben des OS-Befehl tkprof traceFileName.trc tkprof.out
Überprüfen Sie diese Datei - Sie werden einige Overhead-Informationen sehen, aber es wird ein Abschnitt sein, die Ist-Details Ausführungsplan und Statistiken für die Abfrage. Wenn Sie die gleichen Ergebnisse in dieser Information wird dann der nächste Schritt zu sehen ist, ein andere Erklärung (nach der ersten „alten session“) hinzuzufügen, die Informationen darüber, warum die Oracle CBO den Index ignoriert Dump wird:
ALTER SESSION SET EVENTS='10053 trace name context forever, level 1';