Ordine di archiviazione vs Ordine risultato


8

Questa è una domanda derivata dall'ordinamento specificato nella chiave primaria, tuttavia l'ordinamento viene eseguito su SELECT .

Lo dice @Catcall in merito all'ordine di archiviazione (indice cluster) e all'ordine di output

Molte persone credono che un indice cluster garantisca un ordinamento sull'output. Ma non è quello che fa; garantisce un ordine di archiviazione su disco. Vedi, ad esempio, questo post sul blog .

Ho letto il post sul blog di Hugo Kornelis e capisco che un indice non garantisce che il server sql legga i record in un ordine specifico. Eppure faccio fatica ad accettare che non posso assumerlo per il mio scenario?

CREATE TABLE [dbo].[SensorValues](
  [DeviceId] [int] NOT NULL,
  [SensorId] [int] NOT NULL,
  [SensorValue] [int] NOT NULL,
  [Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED 
(
  [DeviceId] ASC,
  [SensorId] ASC,
  [Date] DESC
) WITH (
    FILLFACTOR=75,
    DATA_COMPRESSION = PAGE,
    PAD_INDEX = OFF,
    STATISTICS_NORECOMPUTE = OFF,
    SORT_IN_TEMPDB = OFF,
    IGNORE_DUP_KEY = OFF,
    ONLINE = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS = ON)
  ON [MyPartitioningScheme]([Date])

La mia domanda originale era questa:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC

Ma suggerisco di poter usare anche questo (leggi sotto per la mia spiegazione):

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010

Come puoi vedere, le righe della mia tabella sono piccole (16 byte) e ho solo un indice, un cluster. Nel mio scenario, la tabella è composta da 100.000.000 di record in questo momento (e molto probabilmente aumenterà di dieci volte).

Quando il server di database interroga questa tabella ha due modi per trovare le mie righe, o cerca la chiave primaria e quindi legge e restituisce i miei valori in desc. ordine di data, oppure deve eseguire una scansione completa della tabella. La mia conclusione è che una scansione completa della tabella su tutti quei record sarà troppo lenta e il server di database cercherà quindi sempre la tabella tramite la sua chiave primaria e quindi restituendo i valori ordinati perDate DESC


2
Perché vuoi poter fare così tanto affidamento su questo presupposto? Perché non ci metti un ORDER BYpezzo e sai che puoi fare affidamento su di esso. Vedi n. 3 qui
Aaron Bertrand

Per 2 motivi, curiosità e perché la ORDER BYclausola è un grande successo per me (leggi l' altra domanda per maggiori informazioni). Ho una soluzione che funziona per ora, ma non regge quando e se il mio traffico aumenta.
m__

1
ORDER BY non dovrebbe essere un successo se si fa affidamento sull'ordine che si vede senza l'ordine di - questo non ha senso per me.
Aaron Bertrand

4
L' unica cosa che garantisce l' ordine del set di risultati è una ORDER BYclausola nella tua query. Questo è vero per SQL Server , Oracle , MySQL e qualsiasi altro RDBMS a cui puoi pensare. Prova qualsiasi altra cosa e ti stai preparando per una tazza a sorpresa di FAIL.
Nick Chammas,

Risposte:


15

Vorrei cercare di spiegare perché si dovrebbe non farlo, perché si dovrebbe mai pensare che uno SQL-prodotto restituirà un set di risultati in un ordine specifico, a meno che non si specifica così, qualunque cosa gli indici - cluster o non cluster, B-alberi o R-alberi o kd-alberi o alberi frattali o qualsiasi altro indice esotico utilizzato da un DBMS.


La tua query originale dice al DBMS di cercare la SensorValuestabella, trovare le righe che corrispondono alle 3 condizioni, ordinare quelle righe in ordine Datedecrescente, mantenere solo la prima riga da quelle e, infine, selezionare e restituire solo la SensorValuecolonna.

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC ;

Questi sono ordini molto specifici che hai dato al DBMS e il risultato sarà molto probabilmente lo stesso ogni volta che esegui la query (è possibile che non lo sia, se hai più di una riga che corrisponde alle condizioni e hanno le stesse max Datema diverso, SensorValuema supponiamo per il resto della conversazione che tali righe non esistono nella tabella).

Il DBMS deve fare questo, per eseguire questa query, esattamente come la descrivo sopra? No, certo che no e lo sai. Potrebbe non leggere la tabella ma leggere da un indice. Oppure può usare due indici se pensa che sia meglio (più veloce). O tre. Oppure può utilizzare un risultato memorizzato nella cache (non SQL Server ma altri risultati della query della cache DBMS). Oppure può usare l'esecuzione parallela una volta e non la prossima volta che viene eseguita. Oppure ... (aggiungi qualsiasi altra funzione che influisce sui piani di esecuzione e esecuzione).

Ciò che è garantito, tuttavia, è che restituirà lo stesso risultato esatto, ogni volta che lo esegui, purché non vengano inserite, eliminate o aggiornate righe.


Ora vediamo cosa dice il tuo suggerimento:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010 ;

Questa query dice al DBMS di cercare la SensorValuestabella, trovare le righe che corrispondono alle 3 condizioni, ordinare quelle righe in ordine Datedecrescente, non preoccuparsi dell'ordine, mantenere solo una riga e - infine - selezionare e restituire solo la SensorValuecolonna.

Quindi, sostanzialmente dice lo stesso del primo, tranne che dice che vuoi un risultato solo che soddisfi le condizioni e non ti interessa quale .

Ora, possiamo supporre che darà sempre lo stesso risultato a causa dell'indice cluster?
- Se utilizza questo indice cluster ogni volta, sì.

Ma lo userà?
- No.

Perchè no?
- Perché può. Query Optimizer è libero di scegliere un percorso di esecuzione ogni volta che esegue un'istruzione. Qualunque percorso ritenga opportuno in quel momento per tale affermazione.

Ma utilizzare l'indice cluster non è il modo migliore / più veloce per ottenere risultati?
- No, non sempre. Potrebbe essere la prima volta che si esegue la query. La seconda volta, può utilizzare un risultato memorizzato nella cache (se il DBMS ha una tale funzione, non SQL Server * ). La 1000esima volta che il risultato potrebbe essere stato rimosso dalla cache e un altro risultato potrebbe esistere lì. Supponiamo che tu abbia eseguito questa query poco prima:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date ASC ;         --- Notice the `ASC` here

e il risultato memorizzato nella cache (dalla query sopra) è un altro, diverso che soddisfa ancora le tue condizioni ma non è il primo nel tuo ordine (desiderato). E hai detto al DBMS di non preoccuparti dell'ordine.

OK, quindi solo la cache può influire su questo?
- No, anche molte altre cose.

  • altri indici sono stati considerati, a quel tempo, dal DBMS come migliori per questa query.
  • uno sviluppatore ha modificato o rimosso completamente questo indice cluster che avevi.
  • tu o qualche altro sviluppatore avete aggiunto un altro indice che l'ottimizzatore ha deciso che è più efficiente da utilizzare rispetto all'elemento della configurazione.
  • hai aggiornato a una nuova versione e il nuovo ottimizzatore presenta un bug minore o una modifica nel modo in cui classifica e sceglie i piani di esecuzione.
  • le statistiche sono state aggiornate.
  • è stata invece scelta l'esecuzione parallela.

*: SQL Server non memorizza nella cache i risultati della query ma Enterprise Edition ha una funzione di Scansione avanzata che è simile in quanto è possibile ottenere risultati diversi a causa di query simultanee. Non sono sicuro esattamente quando questo entrerà in gioco però. (grazie a Martin Smith per il suggerimento.)


Spero che tu sia convinto che non dovresti mai fare affidamento sul fatto che una query SQL restituirà risultati in un ordine specifico, a meno che non lo specifichi. E non usarlo mai TOP (n)senza ORDER BY, a meno che ovviamente non vogliate solo n righe nel risultato e non vi importa quali vengano restituite.


2
SQL Server Enterprise Edition ha una funzionalità di Scansione avanzata che è simile in quanto potresti ottenere risultati diversi a causa di query simultanee. Non sono sicuro esattamente quando questo entrerà in gioco però.
Martin Smith,

1
Un'altra cosa che potenzialmente "randomizza" l'ordine dei risultati (anche se apparentemente la query è guidata da un indice ordinato) è il parallelismo. Ho visto che un'app che stava funzionando felicemente su SQL rotto iniziava a comportarsi male dopo aver abilitato il parallelismo automatico (non SQL Server, ma suppongo che potrebbe applicarsi anche lì).
Mat
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.