Garantiert ein IOT eine Bestellung in einem ausgewählten Bereich?

7

Wir müssen priorityeiner Tabelle eine Spalte hinzufügen , die ungefähr 250 Mal pro Sekunde getroffen wird, ungefähr 170 Auswahlen, 125 Einfügungen und 60 Aktualisierungen. Die Spalte wird einfach sein number(1).

Dies priorityspielt keine Rolle für die Einfügungen oder Aktualisierungen, dh nicht Teil des Primärschlüssels, den ich separat erzwingen werde.

Grundsätzlich möchten wir nicht order by170 Mal pro Sekunde einen Scan über einen Bereich durchführen müssen, da die ausgeführte Zahl massiv abfällt.

Gewährleistet eine indexorganisierte Tabelle , priority = 1die beim Ausführen der folgenden Abfrage immer vorher kommt priority = 9:

select *
  from my_table
 where rownum < 2

Für etwas mehr Kontext wäre eine typische Abfrage:

select *
  from my_table
 where mod(to_number(to_char(tstamp,'ss')),1) = 0
   and done is null
   and country = 'gbr'
   and rownum < 2

Die pk-Einschränkung für das IOT würde priority, rest of the pkmit einer separaten Einschränkung für das pk nur für die Struktur werden. doneist in ungefähr 99% der Tabelle null, daher ist dies sowieso nicht sehr selektiv.

Ich denke, der Hauptindex ist, dass country, done, to_number(to_char(tstamp,'ss')wir ungefähr 20 Kombinationen getestet haben, und dieser hat sich bei weitem durchgesetzt.

Ich bin überhaupt nicht bereit, diesen Abfragen eine Zeit hinzuzufügen. 0,01 pro Tag, der von select hinzugefügt wird, beträgt 41 Minuten pro Tag. Wir geben uns lieber mit "gut genug" als mit Perfektion zufrieden.

Ben
quelle
2
Wenn Sie eine hinzufügen ORDER BY priority(wie in Jacks Beispiel), werden Ihre SELECTAbfragen viel langsamer ausgeführt? Welche Indizes haben Sie auf dem Tisch?
Nick Chammas
Sie schlagen vor priority, das IOT als führende Spalte hinzuzufügen ?
Jack sagt, versuchen Sie es mit topanswers.xyz am
@NickChammas, der Prozess ist schon langsam genug. Ich möchte keine zusätzliche (CPU-) Zeit hinzufügen. "gut genug" ist gut genug.
Ben
@ JackDouglas, ja, auf jeden Fall.
Ben
4
@Ben - Verspottet das Hinzufügen der Order-by-Klausel tatsächlich Ihre Abfragepläne oder ist das Leistungsproblem hypothetisch?
ConcernedOfTunbridgeWells

Antworten:

13

Nein.

Das einzige , was die Garantien festgelegte Reihenfolge Ergebnis ist eine ORDER BYKlausel in der Abfrage.

Dies ist eine beliebte Frage zu SQL. Es lohnt sich daher zu wiederholen, was ich als Antwort auf ähnliche Fragen zu SQL Server und MySQL geschrieben habe :

In der SQL-Welt ist die Reihenfolge keine inhärente Eigenschaft eines Datensatzes. Daher erhalten Sie von Ihrem RDBMS keine Garantie dafür, dass Ihre Daten in einer bestimmten Reihenfolge - oder sogar in einer konsistenten Reihenfolge - zurückgegeben werden, es sei denn, Sie fragen Ihre Daten mit einer ORDER BY-Klausel ab.

In Oracle minimiert eine indexorganisierte Tabelle (IOT) den Arbeitsaufwand, den die Datenbank leisten muss, um die Daten in der Sortierreihenfolge des Index zu sortieren. Obwohl Sie möglicherweise feststellen, dass Oracle dazu neigt, aus einem IOT ausgewählte Zeilen in derselben Reihenfolge zurückzugeben, wird Ihnen diese Reihenfolge nur garantiert , wenn Sie das IOT mit einer ORDER BYKlausel abfragen .

Nick Chammas
quelle
Ich dachte schon, hatte aber nicht gehofft :-(. Danke.
Ben
2
Ich denke, Parallelität würde die Ordnung zerstören, wenn Sie sie nicht anfordern.
usr
1
Auch ORDER SIBLINGS BYkann eine Garantie über Ergebnis , um in einer hierarchischen Abfrage zur Verfügung stellen.
Benoit
1
Ich kann Nicks Kommentare nicht mehr verstärken. Entwickler, die implizite Reihenfolge annehmen, können die Quelle einiger ziemlich schrecklicher Fehler sein.
Philᵀᴹ
3
Insbesondere im Zeitrahmen von Oracle 9i oder 10g, als Oracle eine Hash-Gruppierung hinzufügte. Alle Arten von SQL sind kaputt gegangen, weil das, was früher SORT GROUP BY gemacht hat, nicht mehr funktioniert hat.
Adam Musch
5

Garantiert ein IOT eine Bestellung in einem ausgewählten Bereich?

Nein, Bestellung ist ohne nicht garantiert ORDER BY. Je.

Aber so können Sie erreichen, was Sie wollen:

select * from (select * from my_table order by priority) where rownum < 2;

Dies führt nicht unbedingt dazu, dass Oracle mehr Arbeit leistet:

create table foo(priority, id, primary key (priority,id)) organization index as
select mod(level,9), level from dual connect by level<=100000;
select /*+ gather_plan_statistics */ *
from (select * from foo order by priority)
where rownum<2;
PRIORITÄT | ICH WÜRDE
-------: | -:
       0 | 9
select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
| -------------------------------------------------- ----------------------------------------------- |
| | Id | Bedienung | Name | Startet | E-Zeilen | A-Zeilen | A-Zeit | Puffer | |
| -------------------------------------------------- ----------------------------------------------- |
| | 0 | SELECT STATEMENT | | 1 | | 1 | 00: 00: 00.01 | 2 | |
| | * 1 | COUNT STOPKEY | | 1 | | 1 | 00: 00: 00.01 | 2 | |
| | 2 | ANSICHT | | 1 | 1 | 1 | 00: 00: 00.01 | 2 | |
| | 3 | INDEX FULL SCAN | SYS_IOT_TOP_26495 | 1 | 100K | 1 | 00: 00: 00.01 | 2 | |
| -------------------------------------------------- ----------------------------------------------- |
| |
| Prädikatinformationen (identifiziert durch die Operations-ID): |
| -------------------------------------------------- - |
| |
| 1 - Filter (ROWNUM <2) |
| |

dbfiddle hier

Die Bedeutung von COUNT STOPKEYist, dass Oracle nicht alle Zeilen von durchlaufen mussFULL SCAN

Jack sagt, versuchen Sie es mit topanswers.xyz
quelle
2

Nein. Die einzige Möglichkeit, die Reihenfolge der Ergebnisse zu gewährleisten, besteht darin, eine hinzuzufügen ORDER BY.

Justin Cave
quelle
2

Für Microsoft SQL Server lautet die Antwort ebenfalls Nein, und die Mechanik ist ziemlich interessant. Auf der Seite "Online-Bücher" zum Scannen wird das Konzept der Karussellscans im Abschnitt "Erweitertes Scannen" erläutert:

Angenommen, Sie haben eine Tabelle mit 500.000 Seiten. UserA führt eine Transact-SQL-Anweisung aus, die einen Scan der Tabelle erfordert. Wenn dieser Scan 100.000 Seiten verarbeitet hat, führt UserB eine weitere Transact-SQL-Anweisung aus, die dieselbe Tabelle scannt. Das Datenbankmodul plant einen Satz von Leseanforderungen für Seiten nach 100.001 und leitet die Zeilen von jeder Seite an beide Scans zurück. Wenn der Scan die 200.000ste Seite erreicht, führt UserC eine weitere Transact-SQL-Anweisung aus, die dieselbe Tabelle scannt. Ab Seite 200.001 übergibt das Datenbankmodul die Zeilen von jeder Seite, die es liest, an alle drei Scans zurück. Nachdem die 500.000ste Zeile gelesen wurde, ist der Scan für BenutzerA abgeschlossen, und die Scans für BenutzerB und BenutzerC werden zurückgebrochen und beginnen mit dem Lesen der Seiten, die mit Seite 1 beginnen.

Weitere Informationen finden Sie auf der Seite "Bücher online" .

Brent Ozar
quelle
Wann kommt der Karussell-Scan tatsächlich ins Spiel? Ich habe zuvor versucht, dies auf meinem Entwicklercomputer zu sehen, konnte es aber nicht. Kommt es zum Beispiel nur beim Lesen ohne Verpflichtung vor oder hat es andere Einschränkungen?
Martin Smith
@MartinSmith - Sie können die vollständigen Details auf der Seite "Bücher online" lesen. Sie müssen auf Enterprise Edition (nicht Std) sein und mehrere Abfragen müssen eine Tabelle scannen, die zu groß ist, um in den Speicher zu passen.
Brent Ozar
Ich habe die Developer Edition (ich nehme also an, dass dies als Enterprise Edition gilt) mit einer riesigen Tabelle getestet, die viel größer als die RAM-Größe ist, und konnte dies immer noch nicht erreichen. Daher habe ich mich gefragt, ob es noch andere Einschränkungen gibt. Ich könnte es dann noch einmal versuchen, wenn Sie denken, dass es keine gibt.
Martin Smith