2009-11-11 14 views
18

La mia tabella (SQL Server 2008) ha 1 milione + record, quando provo ad ordinare i record per data/ora, ci vuole 1 secondo, ma quando ordino per ID (int), dura solo circa 0,1 secondi.SQL Server 2008: l'ordine per data/ora è troppo lento

C'è un modo per migliorare l'efficienza? (Ho già aggiunto la colonna datetime all'indice)

+0

Quale 'RDBMS' stai usando? – Quassnoi

+0

Sto usando SQL Server 2008 – silent

+7

è quella colonna datetime in un proprio indice separato? Dici "aggiunto .. all'indice" ....se la colonna datetime è ad es. colonna n. 3 in un indice composto, che non aiuta affatto quando si cerca di ordinare da quella colonna datetime da solo ........ –

risposta

23

L'ordinamento tramite id utilizza probabilmente una scansione dell'indice cluster durante l'ordinamento di datetime utilizza l'ordinamento o la ricerca dell'indice.

Entrambi questi metodi sono più lenti di una scansione indice cluster.

Se la tabella è raggruppata per id, in pratica significa che è già stata ordinata. I record sono contenuti in un B+Tree che ha un elenco collegato che collega le pagine nell'ordine id. Il motore dovrebbe solo attraversare l'elenco collegato per ottenere i record ordinati da id.

Se gli id sono stati inseriti in ordine sequenziale, ciò significa che l'ordine fisico delle righe corrisponderà all'ordine logico e la scansione dell'indice cluster sarà ancora più veloce.

Se si desidera che i record da ordinare da datetime, ci sono due opzioni:

  • adottare tutti i record dalla tabella e ordinarli. La lentezza è ovvia.
  • Utilizzare l'indice su datetime. L'indice è memorizzato in uno spazio separato del disco, questo significa che il motore deve passare tra le pagine indice e le pagine tabella in un ciclo annidato. È anche più lento.

Per migliorare l'ordinamento, è possibile creare un indice di copertura separato su datetime:

CREATE INDEX ix_mytable_datetime ON mytable (datetime) INCLUDE (field1, field2, …) 

, e comprendono tutte le colonne che si utilizzano nella query in tale indice.

Questo indice è come una copia shadow della tabella ma con dati ordinati in ordine diverso.

Ciò consentirà di eliminare le ricerche di chiavi (poiché l'indice contiene tutti i dati) che renderà l'ordine entro datetime così veloce come quello id.

Aggiornamento:

un post fresco su questo problema:

+0

Esiste un modo efficace per farlo? – silent

+0

Credo che il database lo abbia comunque archiviato in questo formato (e lo stesso mi piace paragonarlo in questo modo). All'inizio ho pensato la stessa cosa, ma non credo che dovrebbe essere la risposta. – Jrud

+1

+1 Per ottimizzare l'ordinamento per data/ora, impostare l'indice cluster con datetime e l'indice id una chiave primaria non cluster. – Andomar

0

forse se si memorizza DataTime come un int, ma ci sarebbe voluto tempo convertendo ogni volta che si memorizzare o ottenere dati. (tecnica comune utilizzata per archiviare il personale come indirizzo IP e avere tempi di ricerca più rapidi)

si dovrebbe verificare nel server come memorizza datetime, b/c il server lo memorizza già come int o bigint .. sarà non cambiare nulla ....

2

Aggiungere l'ora della data a un nuovo indice, aggiungerlo all'id uno non sarà ancora di grande aiuto.

0

Se il campo data/ora contiene molti valori distinti e tali valori cambiano raramente, definire un indice cluster nel campo datetime, questo ordinerà i dati effettivi per il valore datetime. Vedere http://msdn.microsoft.com/en-us/library/aa933131(SQL.80).aspx per l'uso di indici cluster.

Ciò renderà le ricerche int più lente, poiché verranno relegate utilizzando un indice non cluster.

1

Potrebbe esserci un indice per la colonna int ma non per la colonna datetime? Guarda il piano di esecuzione.

+0

+1 buon punto: controlla il piano di esecuzione! L'indice viene utilizzato a tutti ?? –

0

Hai aggiunto il campo DateTime all'indice "the" o a un indice esclusivo? Stai filtrando la tua selezione per un altro campo e il DateTime o solo questo?

È necessario disporre di un indice con tutti i campi che si stanno filtrando e preferibilmente nello stesso ordine per ottimizzare le prestazioni.

+0

L'ho aggiunto a un indice esistente, ho appena provato a creare un nuovo indice, diventa relativamente più veloce (0,5 secondi), ma ancora più lento di una colonna int. – silent

+0

È importante fare un buon indice guardando i campi nelle istruzioni "WHERE" e "ORDER BY" (e "GROUP BY", se presenti). Dovrebbe essere gli stessi campi e nello stesso ordine. Se non hai bisogno di ogni colonna nella tabella, imposta SELECT solo con i campi desiderati. Quindi svuota la cache e le statistiche e prova i risultati. Pensa anche che sia difficile selezionare alla stessa velocità dell'indice cluster nelle tabelle con molti dati. Questo è il motivo per selezionare attentamente quale dovrebbe essere il cluster. –

6

Per onorare l'ORDER BY Il motore ha due alternative:

  • eseguire la scansione del file utilizzando un indice che offre l'ordine richiesto
  • ordinare le righe

prima opzione è veloce, secondo è lento. Il problema è che per poter essere utilizzato, l'indice deve essere un che copre l'indice. Significa che contiene tutte le colonne nell'elenco di proiezione SELECT e tutte le colonne utilizzate nelle clausole WHERE (come minimo). Se l'indice non copre, il motore dovrebbe cercare l'indice cluster (cioè la 'tabella') per ogni riga, al fine di recuperare i valori delle colonne necessarie. Questa costante ricerca di valori è costosa e c'è un punto di svolta quando il motore (giustamente) decide è più efficiente semplicemente scansionare l'indice cluster e ordinare il risultato, ignorando in effetti l'indice non cluster. Per dettagli, vedere The Tipping Point Query Answers.

considerare i seguenti tre domande:

SELECT dateColumn FROM table ORDER BY dateColumn 
SELECT * FROM table ORDER BY dateColumn 
SELECT someColumn FROM table ORDER BY dateColumn 

Il primo sarà utilizzerà un indice non cluster dateColumn. Ma un secondo non userà un indice su dateColumn, probabilmente sceglierà una scansione e ordinerà invece per le righe 1M. D'altra parte la terza query può beneficiare di un indice su Table(dateColumn) INCLUDE (someColumn).

Questo argomento è trattato in generale su MSDN vedere Index Design Basics, General Index Design Guidelines, Nonclustered Index Design Guidelines o How To: Optimize SQL Indexes.

In definitiva, la scelta più importante del design della tabella è l'indice cluster che si utilizza. Quasi sempre la chiave primaria (di solito un ID auto incrementato) viene lasciata come indice cluster, una decisione che avvantaggia solo determinati carichi OLTP.

Infine, una domanda piuttosto ovvia: perché nel mondo ordinerebbe 1 milione di righe ?? Non puoi mostrarli, vero? Spiegare un po 'di più sul tuo caso d'uso potrebbe aiutarci a trovare una risposta migliore per te.

+0

Grazie Remus, non voglio visualizzare 1 milione + record in una volta, sto usando il metodo row_number() per il paging, ma ho trovato quando provo a sfogliare un numero grande, come pagina 50000 (20 rec/pagina), la query diventa molto lenta, ma se cambio il metodo di ordinamento in ID, diventa quasi 10 volte più veloce. – silent

+1

Ho pensato che questo deve essere l'impaginazione numero_riga. È LINQ, per caso? La cosa migliore da fare è esprimere la query come segue: selezionare gli ID della pagina che ti interessa (edita i 20 ID a pagina 17) e recuperare i dettagli di quei 20 record. Questo * può * essere espresso in T-SQL e anche in LINQ e può essere abbastanza veloce. È meglio pubblicare lo schema e le query coinvolte. –

Problemi correlati