SQL SELECT velocità int vs varchar


110

Sto creando un tavolo e mi sono chiesto.

Se immagazzino, diciamo auto che hanno una marca (fx BMW, Audi ecc.), Farà qualche differenza sulla velocità della query se memorizzo la marca come int o varchar.

Così è

SELECT * FROM table WHERE make = 5 AND ...;

Più veloce / più lento di

SELECT * FROM table WHERE make = 'audi' AND ...;

o la velocità sarà più o meno la stessa?

Risposte:


99

I confronti int sono più veloci dei confronti varchar, per il semplice fatto che gli int occupano molto meno spazio rispetto ai varchar.

Questo vale sia per l'accesso non indicizzato che per quello indicizzato. Il modo più veloce per procedere è una colonna int indicizzata.


Come vedo che hai taggato la domanda postgreql, potresti essere interessato all'utilizzo dello spazio di diversi tipi di data:


13
Ti riferisci a pag. 7.4. Nelle versioni moderne, occupano 1 byte + lunghezza se si dispone di <126 byte. Si noti inoltre che il motivo per cui le stringhe sono molto più lente è spesso che il confronto sensibile alle regole di confronto è estremamente costoso, non che la stringa occupi più spazio. Ma il risultato finale è lo stesso, ovviamente.
Magnus Hagander,

@ Magnus - grazie per l'avvertenza. Sentiti libero di modificare la mia risposta perché vedo che hai abbastanza punti rep.
Robert Munteanu,

"non che la stringa occupi più spazio" ... le stringhe di caratteri al di sopra delle dimensioni minime occupano molto più spazio anche di numeri ad alta precisione, perché un numero (singolare) ha un'unità fissa, le stringhe sono sempre tipi aggregati . 8 byte per un numero a 64 bit 4 byte per carattere in una stringa, inclusi un byte di lunghezza o uno struct; o un altro carattere di terminazione per implementazioni incredibilmente ingenue ...
MrMesees

@RobertMunteanu Hey Robert, mi scuso, so che questo è un vecchio post ma posso gentilmente controllare ... su quanto segue: per interrogare interi, devo collegare ogni colonna di stringa a un'altra tabella (relazione). tuttavia, ciò significa che sono necessarie più operazioni di unione per ciascuna query. Come faccio a determinare se vale la pena fare questo compromesso? Grazie!
AiRiFiEd

2
"I confronti di int sono più veloci dei confronti di varchar, per il semplice fatto che gli int occupano molto meno spazio dei varchar" - questo NON è vero in generale . A seconda del DBMS che usi e dei tipi esatti di dati e delle stringhe che vuoi inserire, potrebbe risultare che i tuoi (diciamo) int a 8 byte sono più lunghi dei varchar ascii che contengono alcuni ID testuali di lunghezza media 3-4 caratteri. Quindi, questa risposta - essendo imprecisa e priva di qualsiasi contesto specifico o risultati sperimentali - non risponde realmente alla domanda. Tutti sanno che i varchar possono occupare molto più spazio degli int, ma NON è necessario.
Marcin Wojnarski

36

Alcuni benchmark approssimativi:

4 milioni di record in Postgres 9.x

Table A = base table with some columns
Table B = Table A + extra column id of type bigint with random numbers
Table C = Table A + extra column id of type text with random 16-char ASCII strings

Risultati su 8 GB di RAM, i7, laptop SSD:

Size on disk:                A=261MB        B=292MB        C=322MB
Non-indexed by id: select count(*), select by id: 450ms same on all tables
Insert* one row per TX:       B=9ms/record        C=9ms/record
Bulk insert* in single TX:    B=140usec/record    C=180usec/record
Indexed by id, select by id:  B=about 200us       C=about 200us

* inserts to the table already containing 4M records

quindi sembra che per questa configurazione, fintanto che i tuoi indici si adattano alla RAM, bigint vs testo a 16 caratteri non fa differenza in termini di velocità.


6
Molto interessante. Come mai la differenza è trascurabile?
Chibueze Opata

18

Sarà un po 'più veloce usando un int invece di un varchar. Più importante per la velocità è avere un indice sul campo che la query può utilizzare per trovare i record.

C'è un altro motivo per utilizzare un int, ovvero normalizzare il database. Invece di avere il testo "Mercedes-Benz" memorizzato migliaia di volte nella tabella, è necessario memorizzare il suo ID e memorizzare il nome del marchio una volta in una tabella separata.


Potresti spiegare di più? Vuoi dire invece di Mercedes-Benzmemorizzare migliaia di volte id 1. Ad esempio tabella car_brands, colonne Brandse Id. Row Mercedes-Benze 1. E nella colonna della tabella principale Brandse nel valore 1. E quando SELECT, poi in un primo momento arriva Iddal tavolo car_brandse poi SELECT Something FROM main_table WHERE Brands = (SELECT Id FROM car_brands WHERE Brands = Mercedes-Benz). O qualche altro approccio?
Andris

3
@ user2118559: Sì, è così che lo memorizzerai. Per ottenere i dati che si userebbero generalmente un join piuttosto che una sottoquery: select something from main_table c inner join car_brands b on b.Id = c.Brands where b.Brands = 'Mercedes-Benz'.
Guffa

Perché il voto negativo? Se non spieghi cosa pensi sia sbagliato, non puoi migliorare la risposta.
Guffa

8

Abbattendo le prestazioni effettive del confronto tra stringhe rispetto a non float, in questo caso qualsiasi dimensione senza segno e con segno non ha importanza. La dimensione è in realtà la vera differenza in termini di prestazioni. Sia 1 byte + (fino a 126 byte) rispetto a 1,2,4 o 8 byte di confronto ... ovviamente i non float sono più piccoli di stringhe e float, e quindi più compatibili con la CPU in assembly.

Il confronto tra stringhe in tutte le lingue è più lento di qualcosa che può essere confrontato in 1 istruzione dalla CPU. Anche il confronto di 8 byte (64 bit) su una CPU a 32 bit è ancora più veloce di un VARCHAR (2) o superiore. * Di nuovo, guarda l'assembly prodotto (anche a mano) ci vogliono più istruzioni per confrontare carattere per carattere che 1 a 8 byte numerici CPU.

Ora, quanto più velocemente? dipende anche dal volume dei dati. Se stai semplicemente confrontando 5 con 'audi' - e questo è tutto ciò che ha il tuo DB, la differenza risultante è così minima che non la vedresti mai. A seconda della CPU, dell'implementazione (client / server, web / script, ecc.) Probabilmente non lo vedrai fino a quando non raggiungerai alcune centinaia di confronti sul server DB (forse anche un paio di migliaia di confronti prima che sia evidente).

  • Per annullare la disputa errata sui confronti degli hash. La maggior parte degli algoritmi di hashing sono lenti, quindi non traggono vantaggio da cose come CRC64 e inferiori. Per oltre 12 anni ho sviluppato algoritmi di ricerca per motori di ricerca multi-contea e 7 anni per le agenzie di credito. Tutto ciò che puoi tenere in numerico il più velocemente ... ad esempio numeri di telefono, codici postali, persino valuta * 1000 (archiviazione) valuta div 1000 (recupero) è più veloce di DECIMAL per i confronti.

Ozz


6

Indice o no, int è molto più veloce (più lungo è il varchar, più lento diventa).

Un altro motivo: l'indice sul campo varchar sarà molto più grande di quello su int. Per tabelle più grandi può significare centinaia di megabyte (e migliaia di pagine). Ciò peggiora notevolmente le prestazioni poiché la sola lettura dell'indice richiede molte letture del disco.


3
Ad esempio di 5 milioni di record di "audi", l'indice non dovrebbe contenere solo una copia della stringa di "audi" e 5 milioni di numeri interi di primary_key? La differenza di dimensione sarebbe davvero così grande, sia vchar o intero?
lulalala

Hai ragione lulalala ma per una colonna che conterrà stringhe casuali la risposta è abbastanza giusta.
Awais fiaz

4

In generale, l'int sarà più veloce. Più lungo è il varchar, più lento diventa


3

Suggerimento: se i valori possibili per il campo make non cambieranno mai (o raramente), puoi utilizzare ENUM come compromesso. Combina una buona velocità con una buona leggibilità.


1
Interessante, come sarà la differenza di velocità tra ENUM e int?
googletorp

PostgresSQL ha un enumtipo di dati? Pensavo fosse specifico per MySQL.
Robert Munteanu,

Postgres ha ENUM, ma non credo che sia implementato allo stesso modo di MySQL. postgresql.org/docs/current/static/datatype-enum.html
googletorp

2
Dal punto di vista delle prestazioni, ENUM dovrebbe funzionare più o meno come int nel campo di ricerca, ma come varchar nell'elenco di destinazione (perché deve trasferire l'intera stringa al client per le righe corrispondenti, non solo l'int)
Magnus Hagander

1
Qui una lettura interessante sul perché NON usare enum in MySQL (solo per aggiungere un po 'di carburante al fuoco: D)
Wilt

1

Se attivi l' indicizzazione su uno dei campi, sarà più veloce. Per quanto riguarda la tua domanda, penso che intsia più veloce di varchar.


0

Un po 'relativo. Sì, gli INT saranno più veloci, ma la domanda è se è evidente nella tua situazione. I VARCHAR sono solo alcune piccole parole o testi più lunghi? e quante righe ci sono nella tabella? Se ci sono solo poche righe, molto probabilmente sarà interamente bufferizzato in memoria (quando richiesto spesso), in quel caso non noterai molta differenza. Poi ovviamente c'è l'indicizzazione, che diventa più importante quando la tabella cresce. L'utilizzo di SSD potrebbe essere più veloce degli HD con query ottimizzate. Anche dei buoni controller del disco a volte velocizzano le query> 10 volte. Ciò potrebbe lasciare spazio al solo utilizzo di VARCHAR che semplifica la lettura e la scrittura di query (non è necessario scrivere join complessi) e velocizza lo sviluppo. I puristi tuttavia non saranno d'accordo e normalizzeranno sempre tutto.

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.