Quando usar o TINYINT sobre INT?

91

Em geral, eu sempre uso Ints. Eu sei que, em teoria, essa não é a melhor prática, pois você deve usar o menor tipo de dados que será garantido para armazenar os dados.

Por exemplo, é melhor usar tinyintquando você sabe que os únicos dados que você armazenará são 1, 0 ou nulo (com uma chance muito pequena de expandi-lo para 2 ou 3 depois).

No entanto, a única razão que conheço para fazer isso é para fins de armazenamento - usando 1 byte em uma linha em vez de 4 bytes.

Quais são os impactos do uso tinyint(ou smallintmesmo bigint) intalém de economizar espaço no disco rígido?

Richard
fonte
2
Este é um questionário muito bom (+1). O MySQL possui SELECT ... PROCEDURE ANALYZE () que realmente recomenda os menores tipos de dados que a tabela deve ter para o SELECT especificado. Essa foi em parte a inspiração por trás da minha resposta.
RolandoMySQLDBA 23/08
3
Boa pergunta, mas para precisar o intervalo tinyint é de 0 a 255. O campo de bit é 0 ou 1 (ou NULL). O custo de armazenamento para um tinyint é de 1 byte. Cada campo de 8 bits em uma tabela custará 1 byte de armazenamento. msdn.microsoft.com/en-us/library/ms187745.aspx e msdn.microsoft.com/en-us/library/ms177603.aspx
billinkc
@billinkc Certo. Foi por isso que mencionei a possibilidade de expandir a coluna para incluir os valores 2 ou 3. Se você incluir 2 ou 3, precisará usar tinyint (na escala muito menor).
Richard
1
"Por exemplo, é melhor usar tinyint quando você sabe que os únicos dados que você armazenará são 1, 0 ou nulo (com uma chance muito pequena de expandi-lo para 2 ou 3 depois)." Eu usaria um ENUM para isso. Eles são armazenados como campos de bits e, como muitos outros apontaram aqui, pequenas economias por registro resultam em grandes economias em todo o banco de dados - ainda mais se a coluna estiver indexada.
2
@ user6665 I'd use an ENUM for such a thing.Não no SQL Server, você não teria, pois ele não possui enumerações de nenhum tipo.
Underscore_d

Respostas:

92

O espaço em disco é barato ... esse não é o ponto!

Pare de pensar em termos de espaço de armazenamento, pense em buffer pool e largura de banda de armazenamento . No extremo, largura de banda do cache da CPU e do barramento de memória . O artigo vinculado faz parte da série, destacando problemas com a seleção de chaves em cluster inadequada (INT x GUID x GUID seqüencial), mas destaca a diferença que os bytes podem fazer.

A mensagem principal é sobre assuntos de design. A diferença não será exibida em um banco de dados individual em um servidor com especificação adequada até você atingir o território VLDB, mas se você puder salvar alguns bytes, por que não fazer isso?

Lembro-me do ambiente descrito em uma pergunta anterior . Mais de 400 bancos de dados, variando em tamanho de 50mb-50GB, por instância SQL. Limpar alguns bytes por registro, tabela e banco de dados nesse ambiente pode fazer uma diferença significativa.

Mark Storey-Smith
fonte
29

Além das outras respostas ...

Linhas e entradas de índice são armazenadas em 8k páginas. Portanto, um milhão de linhas com 3 bytes por linha não tem 3 MB no disco: afeta o número de linhas por página ("densidade da página").

O mesmo se aplica a nvarchar a varchar, smalldatetime a datetime, int a tinyint etc

Editar, junho de 2013

http://sqlblog.com/blogs/joe_chang/archive/2013/06/16/load-test-manifesto.aspx

Este artigo declara

Os critérios importantes são a cardinalidade e a proporção de página para linha.

Portanto, a escolha do tipo de dados importa

gbn
fonte
5
Bom ponto. Um exemplo absoluto de pior caso é uma linha de 4028 bytes composta por colunas de comprimento totalmente fixo às quais você deseja adicionar uma coluna. Adicionar um smallint levaria você a 4030 (2 linhas por página), mas um int o levaria além do limite (1 linha por página, 4028 bytes desperdiçados por página).
Mark-Storey-Smith
Uma vez eu fiz um teste de desempenho no int vs bigint. Economizando 1 milhão de registros, comparando tempo e armazenamento e recuperando-os um por um, medindo novamente o desempenho. Não vi grandes diferenças. Vou fazer o mesmo teste de desempenho para int vs tinyint. Realmente acho que isso pode ser negligenciado em 80% dos aplicativos, resultando em tipos de dados mais consistentes e menores custos de manutenção.
Saeed Neamati
1
@SaeedNeamati Você pode reler o artigo da resposta de Mark (" Você já ouviu falar ... vamos fazer isso - vamos nos preocupar com o desempenho mais tarde? ... ouço isso o tempo todo ... ") e o gbn está aqui . Acho que o que leva para casa é que qualquer escolha ineficiente mostrará suas listras na escala certa, e o intestino da OP não está errado.
Ruffin
14

Não é apenas o armazenamento de tabela que é uma consideração. Se você usar índices nos quais a coluna int faz parte de uma chave composta, naturalmente você desejará que as páginas de índice sejam o mais cheias possível, sendo esse o resultado das entradas de índice serem o menor possível.

Eu definitivamente esperaria descobrir que examinar entradas de índice nas páginas BTREE seria um pouco mais rápido com tipos de dados menores. No entanto, quaisquer VARCHARs envolvidos nas entradas de índice compensariam (anulariam) os ganhos de desempenho ao usar TINYINT sobre INT.

Não obstante, se as entradas de índice tiverem entradas compostas e todas forem números inteiros, quanto menores forem os números inteiros, melhor e mais rápido.

RolandoMySQLDBA
fonte
13

Tudo se torna mais complexo quando os bancos de dados ficam maiores:

  • janelas de manutenção precisam ser ampliadas ou reagendadas
  • backups (o backup completo no final do dia se torna um absurdo, você precisa de um backup diferencial ou mesmo de log e faz o backup completo uma vez por semana, talvez uma vez por mês)
  • as manutenções de desempenho se tornam demoradas (a criação de um índice em uma tabela de vários milhões de linhas não leva tempo trivial para ser executada) e precisa ser remarcada e piorar se a tabela for ampla ...
  • E transmitir esse backup de 100 Gb através da rede não é o que chamo de pedaço de bolo - especialmente se a rede (por algum motivo desconhecido) for teimosa ao deixar cair a conexão na marca de 75 Gb ... (aconteceu com uma instalação em que eu estava trabalhando) estava fazendo backup em uma unidade mapeada na rede - rede) ...

E que tipos de dados têm a ver com isso? TUDO. O uso de tamanhos de linha maiores que o necessário faz com que as páginas do banco de dados sejam preenchidas antes do necessário ou mesmo desperdiçando espaço se o tamanho da linha for tal que não mais que um registro possa ser gravado na página. O resultado são mais páginas necessárias para escrita e leitura, mais memória RAM é usada para armazenar em cache isso (registros maiores precisam de memória maior). E como seus tipos de dados são especificados maiores do que o necessário no disco, seus índices sofrerão o mesmo problema - especialmente se você agrupar a chave primária composta de 2 colunas BIGINT, pois quaisquer outros índices criados copiarão essa chave primária implicitamente em sua definição.

Se você souber que algumas colunas em uma tabela que terão milhões de linhas ou mesmo uma pequena tabela que será FK com vários milhões de linhas que não precisam de um número inteiro de 4 bytes para armazenar seus dados, mas um byte de 2 bytes é suficiente - use SMALLINT . Se os valores no intervalo de 0 a 255 forem suficientes, TINYINT . Um sinalizador Sim / Não? Há BIT .

Fabricio Araujo
fonte
9

Embora para tinyintvs inthaja diferenças claras, como espaço em disco, divisão de páginas e tempo de manutenção, não haveria nenhum deles varchar.

Então, por que não declarar todos os campos de texto como varchar(4000), pois, de qualquer maneira, ele consumirá apenas o espaço necessário? Ainda mais, você terá a garantia de que seus dados nunca serão truncados.

A resposta é obviamente:

  1. Esclarecimento de suas intenções (como ninguém entenderá por que um campo de nome deve ter 4000 caracteres)
  2. Validação, pois você deseja garantir que ninguém entre em uma biografia inteira como o nome.

Essas mesmas razões também se aplicam tinyint.

yoel halb
fonte
3
Este é um segmento mais antigo, mas o esclarecimento e a validação não são a única razão. Se você tiver o VARCHAR (4000) para algo que deve ser VARCHAR (20), o plano de consulta considerará que seus requisitos de memória e CPU são muitos múltiplos do que deveriam ser nessa coluna. Não tomei tempo para fazer isso, mas acho que você provavelmente pode ver isso consultando um plano de consulta para o VARCHAR (20) e depois mude para VARCHAR (4000) e verifique os custos estimados.
3
@GeorgeShouse Demonstração disso aqui
Martin Smith