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.

War es hilfreich?

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)

sah

Es 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';
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top