C'è qualche motivo per preoccuparsi dell'ordine delle colonne in una tabella?


84

So che puoi ALTERARE l'ordine delle colonne in MySQL con PRIMO e DOPO, ma perché dovresti preoccuparti? Dal momento che le buone query nominano esplicitamente le colonne quando si inseriscono i dati, c'è davvero qualche motivo per preoccuparsi in quale ordine sono le colonne nella tabella?

Risposte:


94

L'ordine delle colonne ha avuto un grande impatto sulle prestazioni su alcuni dei database che ho ottimizzato, che abbracciano SQL Server, Oracle e MySQL. Questo post ha buone regole pratiche :

  • Prima le colonne chiave primaria
  • Avanti colonne chiave esterna.
  • Colonne cercate frequentemente dopo
  • Colonne aggiornate frequentemente in seguito
  • Ultime colonne nullable.
  • Colonne nullable meno utilizzate dopo le colonne nullable usate più frequentemente

Un esempio di differenza nelle prestazioni è una ricerca nell'indice. Il motore di database trova una riga in base ad alcune condizioni nell'indice e recupera un indirizzo di riga. Ora dì che stai cercando SomeValue, ed è in questa tabella:

 SomeId int,
 SomeString varchar(100),
 SomeValue int

Il motore deve indovinare dove inizia SomeValue, perché SomeString ha una lunghezza sconosciuta. Tuttavia, se modifichi l'ordine in:

 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.

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


4
@TopBanana: non con varchars, questo è ciò che li differenzia dalle normali colonne char.
Allain Lalonde

1
Non credo che l'ordine delle colonne NELLA TABELLA faccia alcuna differenza - fa decisamente la differenza negli INDICI che potresti creare, vero.
marc_s

4
@TopBanana: non so se conosci Oracle o no, ma non riserva 100 byte per un VARCHAR2 (100)
Quassnoi

1
@Quassnoi: l'impatto maggiore è stato su Sql Server, su una tabella con molte colonne varchar () nullable.
Andomar

7
L'URL in questa risposta non funziona più, qualcuno ha un'alternativa?
scunliffe

41

Aggiornare:

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

Poiché i tipi di dati variabili (come VARCHAR) sono memorizzati con lunghezze variabili in InnoDB, il motore di database dovrebbe attraversare tutte le colonne precedenti in ogni riga per scoprire l'offset di quella data.

L'impatto può raggiungere il 17% per le 20colonne.

Vedi questa voce nel mio blog per maggiori dettagli:

In Oracle, le NULLcolonne finali non consumano spazio, ecco perché dovresti sempre metterle alla fine della tabella.

Anche dentro Oraclee dentro SQL Server, in caso di una riga grande, ROW CHAININGpuò verificarsi un errore.

ROW CHANING sta dividendo una riga che non si adatta a un blocco e si estende su più blocchi, collegati a un elenco collegato.

La lettura delle colonne finali che non si adattavano al primo blocco richiederà l'attraversamento dell'elenco collegato, il che comporterà un'operazione extra I/O.

Vedere questa pagina per l'illustrazione di ROW CHAININGin Oracle:

Ecco perché dovresti mettere le colonne che usi spesso all'inizio della tabella e le colonne che non usi spesso, o le colonne che tendono ad essere NULL, alla fine della tabella.

Nota importante:

Se ti piace questa risposta e vuoi votarla, vota anche per @Andomarla risposta di .

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


1
Quindi stai dicendo che sarebbe lento: seleziona tinyTable.id, tblBIG.firstColumn, tblBIG.lastColumn da tinyTable inner join tblBIG su tinyTable.id = tblBIG.fkID Se i record tblBIG superano gli 8 KB (nel qual caso si verificherebbe un concatenamento di righe ) e il join sarebbe sincrono ... Ma questo sarebbe veloce: seleziona tinyTable.id, tblBIG.firstColumn da tinyTable inner join tblBIG su tinyTable.id = tblBIG.fkID Dal momento che non userei la colonna in altri blocchi, quindi no è necessario attraversare l'elenco collegato Ho capito bene?
jfrobishow

1
Ottengo solo il 6%, e questo è per col1 rispetto a qualsiasi altra colonna.
Rick James,

6

Durante la formazione Oracle in un lavoro precedente, il nostro DBA ha suggerito che mettere tutte le colonne non annullabili prima di quelle nullable era vantaggioso ... anche se TBH non ricordo i dettagli del perché. O forse erano solo quelli che probabilmente sarebbero stati 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'ordinamento da "seleziona *". Non conosco alcun DB che consenta di cambiarli ... beh, non sapevo che MySQL lo permettesse finché non lo hai menzionato.


4
Aveva ragione, Oracle non scrive su disco le colonne NULL finali, salvando alcuni byte. Vedi dba-oracle.com/oracle_tips_ault_nulls_values.htm
Andomar

assolutamente, può fare una grande differenza nella dimensione del disco
Alex

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

Collegamento errato e impossibile trovare l'originale. Anche se puoi cercarlo
Andomar

5

Alcune applicazioni scritte male potrebbero dipendere dall'ordine / indice delle colonne anziché dal nome della colonna. Non dovrebbero esserlo, ma succede. La modifica dell'ordine delle colonne interromperà tali applicazioni.


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

4

Leggibilità dell'output quando devi digitare:

select * from <table>

nel software di gestione del database?

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


4

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

Marc

EDIT: dalla voce di Wikipedia sul database relazionale, ecco la parte rilevante che per me mostra chiaramente che l'ordine delle colonne non dovrebbe mai essere preoccupante:

Una relazione è definita come un insieme di n-tuple. Sia in matematica che nel modello di database relazionale, un insieme è una raccolta non ordinata di elementi, sebbene alcuni DBMS impongano un ordine ai propri dati. In matematica, una tupla ha un ordine e consente la duplicazione. EF Codd originariamente definiva le tuple usando questa definizione matematica. Successivamente, è stata una delle grandi intuizioni di EF Codd che l'uso di nomi di attributi invece di un ordinamento sarebbe stato molto più conveniente (in generale) in un linguaggio informatico basato sulle relazioni. Questa intuizione è ancora utilizzata oggi.


1
Ho visto che la differenza di colonna 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

In quale ambiente SQL sarebbe?
marc_s

1
L'impatto più grande che ho visto è stato su Sql Server 2000, dove lo spostamento in avanti di una chiave esterna ha accelerato alcune query da 2 a 3 volte. Quelle query avevano scansioni di tabelle di grandi dimensioni (1 M + righe) con una condizione sulla chiave esterna.
Andomar

5
RDBMS non dipende dall'ordinamento della tabella a meno che non ti interessi delle prestazioni . Implementazioni diverse avranno penalità di prestazioni diverse per l'ordine delle colonne. Potrebbe essere enorme o potrebbe essere piccolo, dipende dall'implementazione. Le tuple sono teoriche, RDBMS sono pratiche.
Esteban Küber

3
-1. Tutti i database relazionali che ho usato hanno l'ordinamento delle colonne a un certo livello. Se selezioni * da una tabella, non tendi a recuperare le colonne in ordine casuale. Ora su disco vs display è un dibattito diverso. E citare la teoria matematica per sostenere un'ipotesi sulle implementazioni pratiche dei database non ha senso.
DougW

2

L'unico motivo a cui posso pensare è per il debug e la lotta antincendio. Abbiamo una tabella la cui colonna "nome" appare all'incirca al decimo posto nell'elenco. È una seccatura quando fai una selezione rapida * dalla tabella dove id in (1,2,3) e poi devi scorrere per guardare i nomi.

Ma questo è tutto.


1

Come spesso accade, il fattore più importante è il prossimo ragazzo che deve lavorare sul sistema. Cerco di avere prima le colonne della chiave primaria, poi le colonne della chiave esterna e poi il resto delle colonne in ordine decrescente di importanza / significato per il sistema.


In genere iniziamo con l'ultima colonna "creata" (timestamp per quando viene inserita la riga). Con le tabelle più vecchie, ovviamente, possono essere aggiunte diverse colonne dopo di che ... E abbiamo la tabella occasionale in cui una chiave primaria composta è stata cambiata in una chiave surrogata, quindi la chiave primaria è composta da più colonne.
araqnid

1

Se utilizzerai molto UNION, rende più facile la corrispondenza delle colonne se hai una convenzione sul loro ordine.


Sembra che il tuo database debba essere normalizzato! :)
James L

Hey! Riprendilo, non ho detto il mio database. :)
Allain Lalonde


puoi UNIONE con l'ordine delle colonne in 2 tabelle in ordine diverso?
Monica Heddneck

Sì, è sufficiente specificare le colonne in modo esplicito quando si interrogano le tabelle. Con le tabelle A [a, b] B [b, a], ciò significa (SELEZIONA aa, ab DA A) UNIONE (SELEZIONA ba, bb DA B) anziché (SELEZIONA * DA A) UNIONE (SELEZIONA * DA B).
Allain Lalonde

1

Come notato, ci sono numerosi potenziali problemi di prestazioni. Una volta ho lavorato su un database in cui inserire colonne molto grandi alla fine ha migliorato le prestazioni se non hai fatto riferimento a quelle colonne nella tua query. Apparentemente, se un record si estendeva su più blocchi del disco, il motore del database potrebbe interrompere la lettura dei blocchi una volta ottenute tutte le colonne necessarie.

Ovviamente eventuali implicazioni sulle prestazioni dipendono fortemente non solo dal produttore che stai utilizzando, ma anche potenzialmente dalla versione. Qualche mese fa ho notato che il nostro Postgres non poteva usare un indice per un confronto "mi piace". Cioè, se hai scritto "una colonna come 'M%'", non è stato abbastanza intelligente da saltare alle M e uscire quando ha trovato il primo N. Avevo intenzione di cambiare un mucchio di query da usare "tra". Poi abbiamo ottenuto una nuova versione di Postgres e ha gestito i simili in modo intelligente. Sono contento di non essere mai riuscito a cambiare le query. 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 rilevante per me perché scrivo regolarmente codice generico che legge lo schema del database per creare schermate. Ad esempio, le mie schermate di "modifica di un record" sono quasi sempre costruite leggendo lo schema per ottenere l'elenco dei campi e quindi visualizzandoli in ordine. Se cambiassi l'ordine delle colonne, il mio programma continuerebbe a funzionare, ma la visualizzazione potrebbe risultare strana per l'utente. Ad esempio, 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 poi ogni volta che abbiamo aggiunto o rimosso una colonna dovremmo ricordarci di aggiornare il file di controllo. Mi piace dire le cose una volta. Inoltre, quando la schermata di modifica è costruita esclusivamente dallo schema, l'aggiunta di una nuova tabella può significare scrivere zero righe di codice per creare una schermata di modifica, il che è molto interessante. (Bene, ok, in pratica di solito devo aggiungere una voce al menu per chiamare il programma di modifica generico, e generalmente ho rinunciato al generico "seleziona un record da aggiornare" perché ci sono troppe eccezioni per renderlo pratico .)


1

Al di là dell'ovvia ottimizzazione delle prestazioni, mi sono imbattuto in un caso d'angolo in cui il riordino delle colonne causava il fallimento di uno script sql (precedentemente funzionante).

Dalla documentazione "Le colonne TIMESTAMP e DATETIME non hanno proprietà automatiche a meno che non siano specificate esplicitamente, con questa eccezione: per impostazione predefinita, la prima colonna TIMESTAMP ha sia DEFAULT CURRENT_TIMESTAMP che ON UPDATE CURRENT_TIMESTAMP se nessuna delle due è specificata esplicitamente" 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 quel campo è il primo timestamp (o datetime) in una tabella, ma non altrimenti.

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


0

L'unico momento in cui dovrai preoccuparti dell'ordine delle colonne è se il tuo software si basa specificamente su quell'ordine. In genere ciò è dovuto al fatto che lo sviluppatore è diventato pigro e ha fatto un select *e quindi ha fatto riferimento alle colonne per indice piuttosto che per nome nel risultato.


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, elimina la vecchia tabella e rinomina quella nuova. Come puoi immaginare, questa è una scelta molto scarsa per le prestazioni se hai un tavolo grande. Non so se il mio SQL fa lo stesso, ma è uno dei motivi per cui molti di noi evitano di riordinare le colonne. Poiché select * non dovrebbe mai essere utilizzato in un sistema di produzione, l'aggiunta di colonne alla fine non è un problema per un sistema ben progettato. L'ordine delle colonne nella tabella non deve essere modificato in generale.


0

Nel 2002 Bill Thorsteinson ha pubblicato sui forum di Hewlett Packard i suoi suggerimenti per ottimizzare le query MySQL riordinando le colonne. Da allora il suo post è stato letteralmente copiato e incollato almeno un centinaio di volte su Internet, spesso senza citazione. Per citarlo esattamente ...

Regole pratiche generali:

  • Prima le colonne chiave primaria.
  • Avanti colonne chiave esterna.
  • Colonne cercate frequentemente dopo.
  • Colonne aggiornate di frequente in seguito.
  • Ultime colonne nullable.
  • Colonne nullable meno utilizzate dopo colonne nullable usate più di frequente.
  • Blob nella propria tabella con poche altre colonne.

Fonte: forum HP.

Ma quel post è stato fatto tutto nel 2002! Questo consiglio era per MySQL versione 3.23, più di sei anni prima del rilascio di MySQL 5.1. E non ci sono riferimenti o citazioni. Allora, Bill aveva ragione? E come funziona esattamente lo storage engine a questo livello?

  1. Sì, Bill aveva ragione.
  2. Tutto si riduce a una questione di righe concatenate e blocchi di memoria.

Per citare Martin Zahn, un professionista certificato Oracle , in un articolo su The Secrets of Oracle Row Chaining and Migration ...

Le file concatenate ci influenzano in modo diverso. Qui, dipende dai dati di cui abbiamo bisogno. Se avessimo una riga con due colonne distribuite su due blocchi, la query:

SELECT column1 FROM table

dove la colonna1 è nel Blocco 1, non causerebbe alcuna «riga continua di recupero della tabella». Non dovrebbe effettivamente ottenere la colonna 2, non seguirebbe la riga concatenata fino in fondo. D'altra parte, se chiediamo:

SELECT column2 FROM table

e la colonna2 è nel Blocco 2 a causa del concatenamento di righe, quindi vedresti in effetti una «tabella fetch continua riga»

Il resto dell'articolo è una lettura piuttosto buona! Ma sto solo citando la parte qui che è direttamente rilevante per la nostra domanda in esame.

Più di 18 anni dopo, devo dirlo: grazie, Bill!

Mappatura di una riga MySQL a un blocco dati

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.