2009-05-21 3 views

risposta

81

L'ordine delle colonne ha avuto un notevole impatto sulle prestazioni su alcuni database che ho ottimizzato, includendo Sql Server, Oracle e MySQL. Questo post ha good rules of thumb:

  • colonne chiave primaria primi
  • colonne chiave esteri prossimi.
  • Ricerche più frequenti colonne prossima
  • colonne aggiornati frequentemente in seguito
  • colonne Nullable scorso.
  • Least colonne nullable utilizzato dopo le colonne nullable utilizzati più frequentemente

Un esempio per la differenza di prestazioni è una ricerca di indice. Il motore di database trova una riga in base ad alcune condizioni nell'indice e recupera un indirizzo di riga.Ora dire che siete alla ricerca di SomeValue, ed è in questa tabella:

SomeId int, 
SomeString varchar(100), 
SomeValue int 

il motore deve indovinare dove SomeValue inizia, perché SomeString ha una lunghezza sconosciuta. Tuttavia, se si cambia l'ordine di:

SomeId int, 
SomeValue int, 
SomeString varchar(100) 

Ora il motore sa che SomeValue può essere trovato 4 byte dopo l'inizio della riga. Quindi l'ordine delle colonne può avere un notevole impatto sulle prestazioni.

MODIFICA: Sql Server 2005 memorizza i campi a lunghezza fissa all'inizio della riga. E ogni riga ha un riferimento all'inizio di un varchar. Ciò nega completamente l'effetto che ho elencato sopra. Pertanto, per i database recenti, l'ordine delle colonne non ha più alcun impatto.

+0

Ogni motore di database che conosco riserva 100 byte per SomeString, anche se è nullo –

+0

Wow, non lo sapevo. Non deve comunque recuperare l'intero blocco, quindi in realtà non stai risparmiando alcun tempo in I/O, solo la velocità di calcolo quando calcoli l'offset. –

+0

Quindi questo avrebbe un impatto su "selezionare SomeValue da t" ... (sicuramente più a che fare con la restituzione di quel valore da molte righe piuttosto che sulle ricerche sugli indici?) Ma quanto impatto? – araqnid

4

No, l'ordine delle colonne in una tabella del database SQL è totalmente irrilevante, tranne che per scopi di visualizzazione/stampa. Non c'è alcun senso nel riordinare le colonne - la maggior parte dei sistemi non fornisce nemmeno un modo per farlo (tranne il fatto di eliminare la vecchia tabella e ricrearla con il nuovo ordine di colonne).

Marc

EDIT: dalla voce di Wikipedia su database relazionale, ecco la quota di competenza che per me dimostra chiaramente che l'ordine delle colonne dovrebbe mai essere fonte di preoccupazione:

Una relazione è definita come una set di n-tuple. Sia nella matematica che nel modello di database relazionale, un set è una raccolta di articoli non ordinata, sebbene alcuni DBMS impongano un ordine ai propri dati. In matematica, una tupla ha un ordine e consente la duplicazione. E.F. Codd originariamente definito tuple usando questa definizione matematica. Più tardi, fu una delle grandi intuizioni di E.F. Codd che usare nomi di attributi al posto di un ordinamento sarebbe molto più conveniente (in generale) in un linguaggio informatico basato sulle relazioni. Questa intuizione è ancora in uso oggi.

+0

Ho visto che la differenza di colonne ha un grande impatto con i miei occhi, quindi non posso credere che questa sia la risposta giusta. Anche se il voto lo mette al primo posto. Hrm. – Andomar

+0

In che ambiente SQL si troverebbe? –

+1

Il più grande impatto che ho riscontrato era su Sql Server 2000, dove lo spostamento di una chiave esterna in avanti velocizzava alcune query 2-3 volte. Quelle query avevano scansioni di tabelle di grandi dimensioni (1M + righe) con una condizione sulla chiave esterna. – Andomar

4

leggibilità dell'output quando si deve digitare:

select * from <table> 

nel vostro software di gestione dei database?

È una ragione molto spuria, ma al momento non riesco a pensare ad altro.

5

Alcune applicazioni scritte male potrebbero dipendere dall'ordine/indice della colonna anziché dal nome della colonna. Non dovrebbero essere, ma succede. Cambiando l'ordine delle colonne si rompono tali applicazioni.

+2

Gli sviluppatori di applicazioni che rendono il loro codice dipendente dall'ordine delle colonne in una tabella DESERVE di avere le loro applicazioni interrotte. Ma gli utenti dell'applicazione non meritano l'interruzione. – spencer7593

0

L'unica volta che dovrai preoccuparti dell'ordine delle colonne è se il tuo software si basa specificamente su tale ordine. In genere ciò è dovuto al fatto che lo sviluppatore si è pigro e ha fatto un select * e quindi ha fatto riferimento alle colonne per indice anziché per nome nel risultato.

6

Durante l'allenamento Oracle a un lavoro precedente, il nostro DBA ha suggerito che mettere tutte le colonne non annullabili prima dei valori nulli era vantaggioso ... sebbene TBH non ricordi i dettagli del perché. O forse erano solo quelli che erano suscettibili di essere aggiornati dovrebbero andare alla fine? (Forse rimanda a dover spostare la riga se si espande)

In generale, non dovrebbe fare alcuna differenza. Come dici tu, le query dovrebbero sempre specificare le colonne stesse piuttosto che fare affidamento sull'ordine da "seleziona *". Non conosco alcun DB che permetta loro di essere modificati ... beh, non sapevo che MySQL lo permettesse fino a quando non lo hai menzionato.

+4

Aveva ragione, Oracle non scrive le colonne NULL finali su disco, salvando alcuni byte. Vedere http://www.dba-oracle.com/oracle_tips_ault_nulls_values.htm – Andomar

+0

in modo assoluto, può fare una grande differenza nella dimensione del disco – Alex

+0

È il collegamento che intendevi? È correlato alla non indicizzazione di null negli indici piuttosto che all'ordine delle colonne. – araqnid

1

Come spesso accade, il fattore principale è il prossimo che deve lavorare sul sistema. Provo ad avere prima le colonne della chiave primaria, le seconde delle chiavi esterne e poi il resto delle colonne in ordine decrescente di importanza/significato per il sistema.

+0

Iniziamo tipicamente con l'ultima colonna "creata" (data/ora per quando la riga è inserita). Con le tabelle più vecchie, ovviamente, è possibile aggiungere più colonne dopo ... E abbiamo la tabella occasionale in cui una chiave primaria composta è stata modificata in una chiave surrogata, quindi la chiave primaria è più colonne. – araqnid

0

Se si utilizzerà molto UNION, rende più semplici le colonne di corrispondenza se si dispone di una convenzione sul loro ordine.

+0

Sembra che il tuo database abbia bisogno di essere normalizzato! :) –

+0

Ehi! Ritiralo, non ho detto il mio database. :) –

+0

Esistono validi motivi per utilizzare UNION;) Vedere http://www.postgresql.org/docs/current/static/ddl-partitioning.html e http://stackoverflow.com/questions/863867/database-speed-optimization-few-tables-with-many-rows-or-many-tables-with-few-r – voyager

36

Aggiornamento:

In MySQL, ci può essere un motivo per farlo.

Poiché i tipi di dati variabili (come VARCHAR) sono memorizzati in una lunghezza variabile in InnoDB, il motore di database deve attraversare tutte le colonne precedenti in ogni riga per scoprire l'offset di quello dato.

L'impatto può essere pari a 17% per colonne 20.

Vedere questa voce nel mio blog per ulteriori dettagli:

In Oracle, trailing NULL colonne non consumano spazio, è per questo che si dovrebbe sempre metterli alla fine della tabella .

Anche in Oracle e in SQL Server, in caso di una riga di grandi dimensioni, potrebbe verificarsi un ROW CHAINING.

ROW CHANING divide una riga che non rientra in un blocco e si estende su più blocchi, collegati a un elenco collegato.

La lettura delle colonne finali non inserite nel primo blocco richiede l'attraversamento dell'elenco collegato, che comporterà un'operazione supplementare I/O.

Vedi this page per l'illustrazione di ROW CHAINING in Oracle:

Ecco perché si dovrebbe mettere le colonne di uso frequente per l'inizio della tabella, e le colonne non si usa spesso, o le colonne che tendono ad essere NULL, alla fine del tavolo.

Nota importante:

Se ti piace questa risposta e volete votare per esso, si prega di votare anche per @Andomar's answer.

Ha risposto la stessa cosa, ma sembra essere downvoted senza motivo.

+1

Quindi stai dicendo che questo sarebbe stato lento: selezionare tinyTable.id, tblBIG.firstColumn, tblBIG.lastColumn da tinyTable inner join tblBIG su tinyTable.id = tblBIG.fkID Se i record tblBIG sono oltre 8 KB (in tal caso si avrebbe qualche fila concatenamento) e il join sarebbe sincrono ... Ma questo sarebbe veloce: selezionare tinyTable.id, tblBIG.firstColumn da tinyTable join interno tblBIG su tinyTable.id = tblBIG .fkID Poiché non vorrei utilizzare la colonna in altri blocchi, quindi non è necessario attraversare la lista collegata Ho capito bene? – jfrobishow

+1

@jfrobishow: giusto. – Quassnoi

+0

Ricevo solo il 6%, ovvero per col1 rispetto a qualsiasi altra colonna. –

2

L'unico motivo per cui riesco a pensare è per il debug e la lotta antincendio. Abbiamo una tabella la cui colonna "nome" appare circa 10 nella lista. E 'un dolore quando fai una rapida selezione * dalla tabella in cui id in (1,2,3) e poi devi scorrere attraverso per guardare i nomi.

Ma questo è tutto.

0

In generale, ciò che accade in SQL Server quando si modifica l'ordine delle colonne tramite Management Studio, è che crea una tabella temporanea con la nuova struttura, sposta i dati in quella struttura dalla vecchia tabella, rilascia la vecchia tabella e rinomina la nuovo. Come puoi immaginare, questa è una scelta molto scarsa per le prestazioni se hai un grande tavolo. Non so se il mio SQL faccia lo stesso, ma è una delle ragioni per cui molti di noi evitano il riordino delle colonne. Poiché select * non dovrebbe mai essere utilizzato in un sistema di produzione, l'aggiunta di colonne alla fine non è aproblem per un sistema ben progettato. L'ordine delle colonne nella tabella non dovrebbe essere combinato con genral.

0

Come notato, ci sono numerosi problemi di prestazioni potenziali. Una volta ho lavorato su un database in cui mettere colonne molto grandi alla fine ha migliorato le prestazioni se non hai fatto riferimento a quelle colonne nella tua query. Apparentemente, se un record attraversava più blocchi del disco, il motore del database poteva smettere di leggere i blocchi una volta che aveva ottenuto tutte le colonne necessarie.

Naturalmente le implicazioni relative alle prestazioni dipendono non solo dal produttore che si sta utilizzando, ma anche dalla versione. Alcuni mesi fa ho notato che i nostri Postgres non potevano usare un indice per un confronto "mi piace". Cioè, se hai scritto "somecolumn like 'M%'", non è stato abbastanza intelligente da saltare alle M e uscire quando ha trovato il primo N. Ho intenzione di cambiare un sacco di query da usare "between". Poi abbiamo ottenuto una nuova versione di Postgres e ha gestito il simile in modo intelligente. Sono contento di non essere mai riuscito a cambiare le domande. Ovviamente non direttamente rilevante qui, ma il mio punto è che qualsiasi cosa tu faccia per considerazioni sull'efficienza potrebbe essere obsoleta con la prossima versione.

L'ordine delle colonne è quasi sempre molto importante per me perché di routine scrivo codice generico che legge lo schema del database per creare schermate. Ad esempio, le schermate di "modifica di un record" sono quasi sempre costruite leggendo lo schema per ottenere l'elenco dei campi e quindi visualizzarli in ordine. Se avessi cambiato l'ordine delle colonne, il mio programma funzionerebbe ancora, ma il display potrebbe essere strano all'utente. Come, ti aspetti di vedere nome/indirizzo/città/stato/zip, non città/indirizzo/zip/nome/stato. Certo, potrei inserire l'ordine di visualizzazione delle colonne nel codice o in un file di controllo o qualcosa del genere, ma ogni volta che aggiungevamo o rimuovevamo una colonna dovevamo ricordarci di aggiornare il file di controllo. Mi piace dire una volta le cose.Inoltre, quando la schermata di modifica è costruita puramente dallo schema, aggiungere una nuova tabella può significare scrivere zero righe di codice per creare uno schermo di modifica per esso, che è molto interessante. (Beh, okay, in pratica di solito devo aggiungere una voce al menu per chiamare il programma di modifica generico, e generalmente ho rinunciato al generico "selezionare un record da aggiornare" perché ci sono troppe eccezioni per renderlo pratico .)

1

Oltre l'ovvia regolazione delle prestazioni, ho appena trovato un caso d'angolo in cui il riordino delle colonne ha causato il fallimento di uno script sql (precedentemente funzionante).

Dalla documentazione "timestamp e colonne datetime non hanno proprietà automatiche a meno che non vengono specificate in modo esplicito, con questa eccezione: per impostazione predefinita, la prima colonna TIMESTAMP ha sia CURRENT_TIMESTAMP DI DEFAULT e ON UPDATE CURRENT_TIMESTAMP se nessuno dei due è specificato in modo esplicito" https://dev.mysql.com/doc/refman/5.6/en/timestamp-initialization.html

Quindi, un comando ALTER TABLE table_name MODIFY field_name timestamp(6) NOT NULL; funzionerà se tale campo è il primo timestamp (o datetime) in una tabella, ma non altrimenti.

Ovviamente, è possibile correggere il comando alter per includere un valore predefinito, ma il fatto che una query che ha funzionato abbia smesso di funzionare a causa di un riordino della colonna mi ha fatto male alla testa.