Velocidade do SQL SELECT int vs varchar

110

Estou no processo de criação de uma mesa e isso me fez pensar.

Se eu armazenar, digamos, carros que tenham uma marca (fx BMW, Audi ect.), Fará alguma diferença na velocidade da consulta se eu armazenar a marca como um int ou varchar.

Então é

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

Mais rápido / mais lento que

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

ou a velocidade será mais ou menos a mesma?

googletorp
fonte

Respostas:

99

As comparações de int são mais rápidas do que as comparações de varchar, pelo simples fato de que os ints ocupam muito menos espaço do que os varchars.

Isso é verdadeiro para acesso não indexado e indexado. A maneira mais rápida de fazer isso é uma coluna interna indexada.


Como vejo que você marcou a questão postgreql, pode estar interessado no uso do espaço de diferentes tipos de data:

Robert Munteanu
fonte
13
Você está se referindo à página 7.4. Em versões modernas, eles ocupam 1 byte + de comprimento se você tiver <126 bytes. Observe também que o motivo pelo qual as strings são muito mais lentas geralmente é que a comparação sensível ao agrupamento é extremamente cara - não que a string ocupe mais espaço. Mas o resultado final é o mesmo, é claro.
Magnus Hagander
@Magnus - obrigado pelo aviso. Sinta-se à vontade para editar minha resposta, pois vejo que você tem pontos de repetição suficientes.
Robert Munteanu
"não que a string ocupe mais espaço" ... strings de caracteres acima de tamanhos mínimos ocupam muito mais espaço do que até mesmo números de alta precisão, porque um número (singular) tem uma unidade fixa, strings são sempre tipos agregados . 8 bytes para um número de 64 bits 4 bytes por caractere em uma string, incluindo um byte de comprimento ou uma estrutura; ou outro personagem terminator para implementações incrivelmente ingênuas ...
MrMesees
@RobertMunteanu Ei Robert, desculpas, eu sei que este é um post antigo, mas posso verificar ... o seguinte: para consultar inteiros, tenho que vincular cada coluna de string a outra tabela (relacionamento). no entanto, isso significa que mais operações de junção são necessárias para cada consulta. Como posso determinar se essa troca vale a pena? Obrigado!
AiRiFiEd
2
"As comparações de int são mais rápidas do que as comparações de varchar, pelo simples fato de que os ints ocupam muito menos espaço do que os varchars" - isso NÃO é verdade em geral . Dependendo do DBMS que você usa e dos tipos de dados e strings exatos que deseja inserir, pode ser que seus (digamos) ints de 8 bytes sejam maiores do que os varchars ascii contendo alguns IDs textuais de comprimento médio de 3-4 caracteres. Portanto, esta resposta - sendo imprecisa e sem qualquer contexto específico ou resultados experimentais - não responde realmente à pergunta. Todo mundo sabe que os varchars podem ocupar muito mais espaço do que os ints, mas NÃO precisam.
Marcin Wojnarski
36

Algumas referências aproximadas:

4 milhões de registros no 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

Resultados em 8 GB de 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

então parece que para esta configuração, desde que seus índices caibam na RAM, bigint vs texto de 16 caracteres não faz diferença na velocidade.

Grzegorz Luczywo
fonte
6
Muito interessante. Por que a diferença é insignificante?
Chibueze Opata
18

Será um pouco mais rápido usando um int em vez de um varchar. Mais importante para a velocidade é ter um índice no campo que a consulta possa usar para localizar os registros.

Há outra razão para usar um int, que é normalizar o banco de dados. Em vez de ter o texto 'Mercedes-Benz' armazenado milhares de vezes na tabela, você deve armazenar seu id e ter o nome da marca armazenado uma vez em uma tabela separada.

Guffa
fonte
Você poderia explicar mais? Você quer dizer em vez de Mercedes-Benzarmazenar id de milhares de vezes 1. Por exemplo car_brands, tabela , colunas Brandse Id. Row Mercedes-Benze 1. E na coluna Brandse valor da tabela principal 1. E quando SELECT, então primeiro saia Idda mesa car_brandse depois SELECT Something FROM main_table WHERE Brands = (SELECT Id FROM car_brands WHERE Brands = Mercedes-Benz). Ou alguma outra abordagem?
Andris de
3
@ user2118559: Sim, é assim que você o armazenaria. Para obter os dados que você geralmente usam uma junção em vez de uma subconsulta: select something from main_table c inner join car_brands b on b.Id = c.Brands where b.Brands = 'Mercedes-Benz'.
Guffa
Por que o downvote? Se você não explicar o que acha que está errado, isso não pode melhorar a resposta.
Guffa
8

Dividindo o desempenho real da comparação de string versus não flutuantes, neste caso, qualquer tamanho não assinado e assinado não importa. O tamanho é realmente a verdadeira diferença no desempenho. Seja 1byte + (até 126 bytes) versus 1,2,4 ou comparação de 8 bytes ... obviamente não flutuantes são menores do que strings e flutuadores e, portanto, mais amigáveis ​​à CPU em montagem.

A comparação string a string em todos os idiomas é mais lenta do que algo que pode ser comparado em uma instrução pela CPU. Mesmo comparar 8 bytes (64 bits) em uma CPU de 32 bits ainda é mais rápido do que um VARCHAR (2) ou maior. * Novamente, olhe para o assembly produzido (mesmo à mão), é preciso mais instruções para comparar char por char do que numérico CPU de 1 a 8 bytes.

Agora, quanto mais rápido? depende também do volume de dados. Se você estiver simplesmente comparando 5 com 'audi' - e isso é tudo que o seu banco de dados possui, a diferença resultante é tão mínima que você nunca a veria. Dependendo da CPU, implementação (cliente / servidor, web / script, etc) você provavelmente não verá até que faça algumas centenas de comparações no servidor de banco de dados (talvez até alguns milhares de comparações antes que seja perceptível).

  • Para anular a disputa incorreta sobre comparações de hash. A maioria dos algoritmos de hash são lentos, então você não se beneficia de coisas como CRC64 e menores. Por mais de 12 anos desenvolvi algoritmos de busca para mecanismos de busca multi-condados e 7 anos para agências de crédito. Qualquer coisa que você possa manter em números mais rápido ... por exemplo, números de telefone, códigos postais, até mesmo moeda * 1000 (armazenamento) moeda div 1000 (recuperação) é mais rápido do que DECIMAL para comparações.

Ozz

Ozz Nixon
fonte
6

Índice ou não, int é muito mais rápido (quanto mais longo o varchar, mais lento ele fica).

Outro motivo: o índice no campo varchar será muito maior do que no int. Para tabelas maiores, pode significar centenas de megabytes (e milhares de páginas). Isso torna o desempenho muito pior, pois apenas a leitura do índice requer muitas leituras de disco.

Konrad Garus
fonte
3
Por exemplo, de 5 milhões de registros de "audi", o índice não manteria apenas uma cópia da string de "audi" e 5 milhões de inteiros de primary_key? A diferença de tamanho seria realmente tão grande, seja vchar ou inteiro?
lulalala
Você está certo lulalala, mas para uma coluna que irá conter strings aleatórias, a resposta é justa.
Awais fiaz de
4

Em geral, o int será mais rápido. Quanto mais longo é o varchar, mais lento ele fica

anthares
fonte
3

DICA: Se os valores possíveis para o campo make vai nunca mais (ou raramente) a mudança, você pode usar ENUM como um compromisso. Combina boa velocidade com boa legibilidade.

Thomas Schaub
fonte
1
Interessante, qual será a diferença de velocidade entre ENUM e int?
googletorp
O PostgresSQL possui um enumtipo de dados? Achei que fosse específico do MySQL.
Robert Munteanu
Postgres tem ENUM, mas não acho que seja implementado da mesma forma que o MySQL. postgresql.org/docs/current/static/datatype-enum.html
googletorp
2
Em termos de desempenho, ENUM deve executar mais ou menos o mesmo que int no campo de pesquisa, mas como varchar na lista de destino (porque ele tem que transferir toda a string para o cliente para linhas correspondentes, não apenas o int)
Magnus Hagander
1
Aqui está uma leitura interessante sobre por que NÃO usar enum no MySQL (apenas para adicionar um pouco de combustível ao fogo: D)
Wilt em
1

Se você ativar a indexação em qualquer um dos campos, será mais rápido. Quanto à sua pergunta, acho que inté mais rápido do que varchar.

Sarfraz
fonte
0

Um tanto relativo. Sim, INTs serão mais rápidos, mas a questão é se isso é perceptível em sua situação. Os VARCHARs são apenas algumas palavras pequenas ou textos mais longos? e quantas linhas há na tabela? Se houver apenas algumas linhas, provavelmente será totalmente armazenado em buffer na memória (quando solicitado com freqüência), nesse caso, você não notará muita diferença. Então, é claro, há a indexação, que se torna mais importante quando a tabela cresce. Usar SSDs pode ser mais rápido do que HDs com consultas otimizadas. Além disso, bons controladores de disco às vezes aceleram as consultas> 10x. Isso pode deixar espaço para apenas o uso de VARCHARs, o que torna mais fácil ler e escrever consultas (sem necessidade de escrever junções complexas) e acelerar o desenvolvimento. Os puristas, entretanto, irão discordar e sempre normalizarão tudo.

Alex
fonte