2010-02-27 7 views
74

Je suis en train de créer une table et cela m'a fait réfléchir. Si je stocke, disons les voitures qui ont une marque (fx BMW, Audi ect.), Cela fera-t-il une différence sur la vitesse de requête si je stocke la marque comme int ou varchar.SQL SELECT vitesse int vs varchar

Alors est

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

plus rapide/plus lent que

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

ou sera la vitesse plus ou moins la même chose?

+1

Merci pour toutes vos réponses et informations supplémentaires. Vous avez prouvé ma suspicion et facilité mon choix. – googletorp

Répondre

72

Les comparaisons int sont plus rapides que les comparaisons varchar, pour le simple fait que les ints occupent beaucoup moins d'espace que les varchars.

Ceci est vrai à la fois pour l'accès non indexé et indexé. Le moyen le plus rapide d'aller est une colonne int indexée.


Comme je vois que tu as étiqueté la postgreql question, vous pourriez être intéressé par l'utilisation de l'espace des différents types de date:

+9

Vous faites référence à la page 7.4. Dans les versions modernes, ils prennent 1 octet + longueur si vous avez <126 octets.Notez également que la raison pour laquelle les chaînes sont beaucoup plus lentes est souvent que la comparaison sensible au classement est extrêmement coûteuse - pas que la chaîne prenne plus de place. Mais le résultat final est le même, bien sûr. –

+0

@Magnus - merci pour le heads-up. N'hésitez pas à modifier ma réponse car je vois que vous avez suffisamment de points de rep. –

+0

"pas que la chaîne prenne plus d'espace" ... les chaînes de caractères au-dessus des tailles minimales occupent beaucoup plus d'espace que les nombres de haute précision, car un nombre (singulier) a une unité fixe, les chaînes sont toujours agrégées les types. 8 octets pour un nombre de 64 bits 4 octets par caractère dans une chaîne, y compris un octet de longueur ou struct; ou un autre caractère de terminaison pour des implémentations incroyablement naïves ... – MrMesees

1

Si vous activez en indexant dans l'un des champs, ce sera plus rapide. En ce qui concerne votre question, je pense que int est plus rapide que varchar.

4

En général, l'int sera plus rapide. Plus est le varchar plus il devient lent

2

Astuce: Si les valeurs possibles pour le champ font sera ne changera jamais (ou rarement), vous pouvez utiliser ENUM comme un compromis. Il combine une bonne vitesse avec une bonne lisibilité.

+1

Intéressant, Quelle sera la différence de vitesse entre ENUM et int? – googletorp

+0

Est-ce que PostgresSQL a un type de données 'enum'? Je pensais que c'était spécifique à MySQL. –

+0

Postgres a ENUM, mais je ne pense pas qu'il soit implémenté de la même manière que MySQL. http://www.postgresql.org/docs/current/static/datatype-enum.html – googletorp

15

Il sera un peu plus rapide d'utiliser un int au lieu d'un varchar. Plus important pour la vitesse est d'avoir un index sur le champ que la requête peut utiliser pour trouver les enregistrements.

Il existe une autre raison d'utiliser un int, et c'est de normaliser la base de données. Au lieu d'avoir le texte «Mercedes-Benz» stocké des milliers de fois dans la table, vous devez stocker son identifiant et enregistrer le nom de la marque une fois dans un tableau séparé.

+0

Pourriez-vous expliquer plus? Voulez-vous dire au lieu de 'Mercedes-Benz' pour stocker des milliers de fois id' 1'. Par exemple, la table 'car_brands', les colonnes' Brands' et 'Id'. Rangée "Mercedes-Benz" et "1". Et dans la colonne du tableau principal «Marques» et la valeur «1». Et quand 'SELECT', alors d'abord obtenir' Id' de la table 'car_brands', puis' SELECT Quelque chose FROM main_table WHERE Marques = (SELECT ID FROM car_brands WHERE Marques = Mercedes-Benz) '. Ou une autre approche? – user2118559

+3

@ user2118559: Oui, c'est comme ça que vous le stockez. Pour obtenir les données, vous utiliserez généralement une jointure plutôt qu'une sous-requête: 'sélectionnez quelque chose de main_table c interne joignez car_brands b sur b.Id = c.Marques où b.Brands = 'Mercedes-Benz''. – Guffa

+0

Pourquoi le downvote? Si vous n'expliquez pas ce que vous pensez être faux, cela ne peut pas améliorer la réponse. – Guffa

4

Index ou pas, int est beaucoup plus rapide (plus le varchar est long, plus il est lent).

Une autre raison: le champ index sur varchar sera beaucoup plus grand que sur int. Pour les grandes tables, cela peut signifier des centaines de mégaoctets (et des milliers de pages). Cela rend la performance bien pire que la lecture de l'index seul nécessite de nombreuses lectures de disque.

+1

Par exemple de 5 millions d'enregistrements de "audi", l'index ne contiendrait-il qu'une seule copie de la chaîne "audi" et 5 millions entiers de la clé primaire? Est-ce que la différence de taille serait vraiment aussi grande, que ce soit vchar ou integer? – lulalala

6

En démontant les performances réelles de la comparaison de chaînes par rapport aux non-flottants, dans ce cas, toute taille non signée et signée n'a pas d'importance. La taille est en fait la vraie différence de performance. Soit 1 octet + (jusqu'à 126 octets) contre 1,2,4 ou 8 octets de comparaison ...évidemment les non flottants sont plus petits que les chaînes et les flottants, et donc plus conviviaux pour le CPU dans l'assemblage.

La comparaison de chaîne à chaîne dans tous les langues est plus lente que quelque chose qui peut être comparé en 1 instruction par la CPU. Même la comparaison de 8 octets (64 bits) sur un processeur 32 bits est toujours plus rapide qu'avec un VARCHAR (2) ou plus. * Encore une fois, regardez l'assemblage produit (même à la main) il faut plus d'instructions pour comparer char par char que 1 à 8 octets CPU numérique.

Maintenant, combien plus vite? dépend également du volume de données. Si vous comparez simplement 5 à 'audi' - et c'est tout ce que votre DB a, la différence qui en résulte est si minime que vous ne la verrez jamais. En fonction du CPU, de l'implémentation (client/serveur, web/script, etc.), vous ne le verrez probablement pas tant que vous n'aurez pas effectué quelques centaines de comparaisons sur le serveur DB (peut-être même quelques milliers de comparaisons).

  • Pour annuler le conflit incorrect concernant les comparaisons de hachage. La plupart des algorithmes de hachage eux-mêmes sont lents, donc vous ne bénéficiez pas de choses comme CRC64 et plus petit. Pendant plus de 12 ans, j'ai développé des algorithmes de recherche pour les moteurs de recherche multi-comté et 7 ans pour les bureaux de crédit. Tout ce que vous pouvez garder en numérique le plus rapidement ... par exemple les numéros de téléphone, les codes postaux, même la monnaie * 1000 (stockage) la devise div 1000 (récupération) est plus rapide que DECIMAL pour les comparaisons.

Ozz

0

Un peu relatif. Oui, les INT seront plus rapides, mais la question est de savoir si cela est perceptible dans votre situation. Les VARCHAR ne sont-ils que de petits mots ou des textes plus longs? et combien de lignes y a-t-il dans la table? S'il n'y a que quelques lignes, elles seront probablement entièrement mises en mémoire tampon (à la demande souvent), dans ce cas vous ne remarquerez pas beaucoup de différence. Alors, bien sûr, il y a l'indexation, qui devient plus importante quand la table grandit. L'utilisation de SSD peut être plus rapide que celle de HD avec des requêtes optimisées. De bons contrôleurs de disque accélèrent parfois les requêtes> 10x. Cela pourrait laisser place à l'utilisation de VARCHARs, ce qui facilite la lecture et l'écriture des requêtes (pas besoin d'écrire des jointures complexes) et accélère le développement. Les puristes seront cependant en désaccord et normaliseront toujours tout.

16

Quelques repères rugueux:

4 millions de disques dans 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 

Résultats sur 8 Go de RAM, Core i7, ordinateur portable 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 

de sorte qu'il ressemble à cette configuration, tant que vos index tiennent dans la RAM, le texte bigint vs 16-char ne fait aucune différence de vitesse.

+0

Très intéressant. Comment se fait-il que la différence soit négligeable? –