Declarando tipos numéricos no MySQL

Artigo que explica como escolher, com eficiência, os tipos numéricos de colunas de tabelas de bancos de dados MySQL.

golfinho, que é o animal símbolo do MySQL
Introdução

MySQL é um SGBD muito popular, mas muito robusto. Por ser robusto e cheio de recursos, a documentação do MySQL não poderia ser diferente: também é muito extensa. Talvez seja por este motivo que nem sempre ela é devidamente estudada e, com isso, nota-se que muita gente acaba utilizando os recursos disponíveis de forma incorreta, seja por desconhecimento ou descuido.

Neste artigo, veremos sobre um destes enganos comuns de utilização do MySQL: a má especificação dos tipos numéricos nas colunas de tabelas MySQL.


Escolhendo o tipo numérico ideal para uma coluna no MySQL

Para escolher o tipo de dado ideal para colunas com valores numéricos no MySQL, primeiro é necessário responder às seguintes perguntas:

  1. Os valores serão usados para realizar contas e/ou usados para ordenação de resultados de consultas?
  2. Serão guardados valores inteiros (integer) ou reais (float)?
  3. Serão guardados apenas valores positivos ou podem existir valores negativos?
  4. Qual é o maior e o menor valor aceito ou a precisão de casas decimais aceita?
  5. Os valores precisam ser preenchidos com zeros a esquerda ou tem uma largura esperada?

1 - Os valores serão usados para realizar contas e/ou usados para ordenação de resultados de consultas?

A resposta da primeira pergunta é crucial para determinar se você realmente precisa de um campo numérico ou um campo textual. Embora pareça contraditório, você não precisa declarar todos os campos que armazenam números em campos de tipos numéricos. Um exemplo muito comum é o número de um endereço. Algumas pessoas declaram o "logradouro", "bairro", "cidade", etc. como campos textuais (correto), mas declaram o "número" do endereço como "INT" (incorreto). Só que dificilmente você precisará fazer contas com este campo e nem ordenar resultados com base no número do endereço. E isso sem entrar no mérito que existem endereços que possuem números e letras, como "51A" e "51B". Portanto, o ideal é que se utilize um campo textual para guardar o número de um endereço (normalmente VARCHAR).


2 - Serão guardados valores inteiros (integer) ou reais (float)?

Uma vez determinado que você realmente precisa de um campo numérico, é simples determinar se serão usados apenas números inteiros ou se serão usados números reais (números com casas decimais diferente de zero).


3 - Serão guardados apenas valores positivos ou podem existir valores negativos?

Também é simples determinar se serão usados apenas números positivos ou se também serão usados números negativos. Para campos que aceitam apenas números positivos (incluindo o zero), usa-se o modificador "UNSIGNED" (sem sinal), enquanto que os campos que aceitam números positivos e negativos, utiliza-se o modificador "SIGNED" (com sinal). Quando não é especificado nenhum destes modificadores, o campo é considerado "SIGNED" por padrão. Portanto, não é comum (nem necessário) especificar que o campo é "SIGNED", a não ser por questões de legibilidade (deixar explicito que o campo precisa de valores negativos).


4 - Qual é o maior e o menor valor aceito ou a precisão de casas decimais aceita?

A resposta da quarta pergunta é a mais importante no que tange a otimização e performance do banco de dados. Existem 5 tipos de campos inteiros e 3 tipos de campos reais, e cada tipo utiliza uma quantidade diferente de bytes para armazenar o número. Consequentemente, cada tipo aceita uma faixa de números mais ampla ou mais reduzida.

Capacidades dos tipos inteiros no MySQL
Tipo Bytes Faixa de valores
SIGNED UNSIGNED
Mín. Máx. Mín. Máx.
TINYINT 1 -128127 0255
SMALLINT 2 -32.76832.767 065.535
MEDIUMINT 3 -8.388.6088.388.607 016.777.215
INT 4 -2.147.483.6482.147.483.647 04.294.967.295
BIGINT 8 -9.223.372.036.854.775.8089.223.372.036.854.775.807 018.446.744.073.709.551.615

Observação: "INTEGER" é uma forma alternativa para "INT".

Note que a especificação de SIGNED ou UNSIGNED influencia no menor e maior valor aceito por cada tipo inteiro. Vale ressaltar que quanto menos bytes tem o campo, mais rápidas são as operações realizadas sobre ele (inclusive para ordenação).

No caso dos campos reais, é importante conhecer a precisão do campo e a quantidade de casas decimais acurada. A "precisão" é a quantidade de dígitos (ignorando sinal e pontuação), enquanto a quantidade de casas decimais é a quantidade de dígitos após a vírgula (por exemplo "-102,46" tem 5 dígitos de precisão e 2 dígitos de casas decimais). No MySQL, os campos FLOAT e DOUBLE têm um número fixo de bytes e são usados para valores reais aproximados (dependendo da quantidade de dígitos inteiros, a acuracidade dos dígitos das casas decimais pode ser prejudicada). Portanto, a acuracidade dos valores das casas decimais dos tipos FLOAT e DOUBLE é aproximada. Já o tipo DECIMAL é usado para números reais exatos, logo, é o tipo de campo mais indicado para evitar perdas de precisão (por exemplo, usar para valores monetários). A especificação de SIGNED e UNSIGNED para campos reais é usada apenas para permitir ou não valores negativos.

Capacidades dos campos reais no MySQL
Tipo Bytes Precisão Casas decimais
FLOAT 4 1 a 24 ~7
DOUBLE 8 1 a 53 ~15
DECIMAL - 0 a 65 0 a 30

Observação: "REAL" e "DOUBLE PRECISION" são formas alternativas para "DOUBLE". enquanto "NUMERIC", "DEC" ou "FIXED" são formas alternativas para "DECIMAL".

É possível especificar FLOAT(P), onde "P" é a precisão do campo. O MySQL converte o campo para FLOAT ou para DOUBLE de acordo com o valor de "P" (até precisão 24 é convertido para FLOAT e de 24 a 53 é convertido para DOUBLE).

Também é possível especificar FLOAT(P,D) ou DOUBLE(P,D) ou DECIMAL(P,D), onde "P" é a precisão do campo e "D" é a quantidade de casas decimais esperada pelo campo.


5 - Os valores precisam ser preenchidos com zeros a esquerda ou tem uma largura esperada?

A resposta da quinta pergunta é usada apenas para formatação do número. Se quisermos que os números sejam devolvidos com zeros a esquerda, utilizamos o modificador "ZEROFILL". Já a "largura" dos campos é usada para que a aplicação possa exibir o valor com espaços a esquerda. A largura dos campos é devolvida entre as meta-informações vindas de uma consulta.

A largura é especificada de forma diferente para inteiros e reais. Nos números inteiros, a largura é especificada entre parênteses, após o nome do campo (por exemplo "INT(11)"). Para os números reais, a largura é justamente a precisão do campo (citada anteriormente), a diferença é que o número da precisão passa a ser a largura total do campo, inclusive com a pontuação.

A maior confusão que vejo por aí é a utilização da "largura" do campo achando que ela é a "capacidade máxima de dígitos" do campo. Isso está errado. Ou seja, se o campo é INT(1), INT(2) ou INT(11), seu valor máximo continuará sendo "2.147.483.647". Para especificar campos com maior ou menor capacidade, devem ser usadas as variações do campo (TINYINT, SMALLINT, MEDIUMINT ou BIGINT para campos INT ou usar FLOAT ou DOUBLE para campos de ponto flutuante).

Observação: a opção ZEROFILL aplica automaticamente a opção UNSIGNED no campo, mesmo que você tenha especificado SIGNED explicitamente.


Além das opções mostradas acima, os campos do MySQL também podem ter outras características como: aceitar valores NULL ou não, e se o número (inteiro) terá seu valor automaticamente preenchido de acordo com uma sequência incremental (AUTO_INCREMENT).

Outra observação é que o MySQL oferece o tipo "SERIAL", que é a abreviação para: "BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE".

3 comentários