Become a member!

SERIAL ou IDENTITY no PostgreSQL? A escolha de auto-incremento que a maioria dos schemas erra

🌐
Este artigo também está disponível em outros idiomas:
🇪🇸 Español  •  🇩🇪 Deutsch  •  🇬🇧 English

Quando o assunto é gerar primary keys auto-incrementais no PostgreSQL, a escolha entre os tipos “identity” e “serial” tem consequências importantes para o design e o desempenho do seu banco de dados. Neste artigo vamos ver as principais diferenças entre as duas opções e resumir as boas práticas para você decidir com conhecimento de causa.

O que são identities e tipos serial

Tanto as “identities” quanto os tipos “serial” servem para gerar automaticamente valores únicos de primary key. Mas a implementação e os recursos de cada um são diferentes.

🔔 Outra forma de criar valores auto-incrementais são as sequences puras. Neste artigo não vamos falar delas porque, em muitos casos, você quer usar as sequences “por trás” de serials ou identities, sem se preocupar em manipulá-las diretamente. Mesmo assim, em alguns casos as sequences permitem implementar numerações “fora do comum” (por exemplo, um identificador único para todos os registros do banco ou para um conjunto de tabelas).

Tipos serial

“Serial” é um recurso específico do PostgreSQL que cria uma coluna inteira ligada a uma sequence. É um atalho para criar uma sequence e uma coluna inteira. Os tipos de dados serial não são tipos de verdade, apenas uma conveniência de notação para criar colunas de identificador único (parecida com a propriedade AUTO_INCREMENT suportada por MySQL, MariaDB, MSSQLServer e outros bancos).

Os valores inteiros gerados ficam limitados aos seguintes tipos de dados inteiros.

Os tipos serial são: smallserial, serial e bigserial.

NomeTamanho de armazenamentoDescriçãoIntervalo
smallserial2 bytesinteiro auto-incremental pequeno1 a 32767
serial4 bytesinteiro auto-incremental1 a 2147483647
bigserial8 bytesinteiro auto-incremental grande1 a 9223372036854775807

Declarar uma tabela com uma primary key serial fica mais ou menos assim:

CREATE TABLE people (
    people_id bigserial primary key,
    first_name varchar,
    last_name varchar
)

o que equivale a executar as seguintes instruções:

CREATE SEQUENCE people_people_id_seq AS bigint;
CREATE TABLE people (
    people_id bigint NOT NULL DEFAULT nextval('people_people_id_seq') primary key ,
    first_name varchar,
    last_name varchar    
);
ALTER SEQUENCE people_people_id_seq OWNED BY people.people_id;

Como você pode ver, criar um campo bigserial é um atalho para:

  • Criar uma coluna bigint e fazer com que seus valores default venham de um gerador de sequence.
  • Aplicar uma constraint NOT NULL para garantir que não seja possível inserir um valor nulo.
  • Marcar a sequence como owned by da coluna, de modo que ela seja removida se a coluna ou a tabela for removida.

Mais informações sobre os tipos serial estão na documentação do PostgreSQL.

Identities

  • Introduzidas no PostgreSQL 10, as “identities” seguem o padrão SQL.
  • Separam o conceito de geração da identidade do tipo de dado, o que dá mais liberdade na escolha do tipo de dado da primary key.
  • Permitem um controle fino das propriedades, como definir se as atualizações são permitidas, e convivem com várias constraints.
  • As identities são mais simples de gerenciar.

Uma tabela que usa uma IDENTITY como primary key gerada automaticamente é declarada assim:

CREATE TABLE people (
   people_id bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
   first_name varchar,
   last_name varchar
)

ou assim

CREATE TABLE people (
   people_id bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
   first_name varchar,
   last_name varchar
)

Sobre a cláusula IDENTITY, a documentação do PostgreSQL diz:

A cláusula IDENTITY cria a coluna como coluna identity. Ela terá uma sequence implícita associada, e a coluna nas novas linhas receberá automaticamente os valores da sequence. Essa coluna é implicitamente NOT NULL.

Certo, mas qual é a diferença entre as cláusulas ALWAYS e BY DEFAULT?

As cláusulas ALWAYS e BY DEFAULT determinam como os valores informados explicitamente pelo usuário são tratados nos comandos INSERT e UPDATE.

Em um comando INSERT, se ALWAYS estiver selecionado, um valor informado pelo usuário só é aceito se a instrução INSERT especificar OVERRIDING SYSTEM VALUE. Se BY DEFAULT estiver selecionado, o valor informado pelo usuário tem precedência.

Em um comando UPDATE, se ALWAYS estiver selecionado, qualquer atualização da coluna para um valor diferente de DEFAULT será rejeitada. Se BY DEFAULT estiver selecionado, a coluna pode ser atualizada normalmente. (Não existe cláusula OVERRIDING para o comando UPDATE.)

Mais informações sobre as identities estão na documentação do PostgreSQL

Boas práticas

Então, qual é melhor e por quê?

Clareza e aderência ao padrão: Use “identities” para deixar o schema mais claro. Elas deixam explícita a finalidade da coluna e seguem o padrão SQL, o que melhora a legibilidade e a manutenção.

Portabilidade e interoperabilidade: As “identities” são mais compatíveis com as práticas do SQL padrão e facilitam a integração quando você migra bancos de dados ou trabalha com desenvolvedores acostumados às convenções padrão.

Integridade dos dados e manutenção: Use “identities” quando o foco é manter a integridade dos dados e fazer valer as constraints. Poder controlar as propriedades dá uma abordagem completa para lidar com atualizações e constraints. Além disso, como serial não é um tipo de verdade, não pode ser usado em todas as instruções em que um tipo de campo real pode. Você pode indicar serial como tipo de coluna ao criar uma tabela ou ao adicionar uma coluna. Mas tirar o “serial” de uma coluna existente, ou colocá-lo em uma coluna existente, não é tão simples.

Adaptabilidade a longo prazo: Se você prevê mudanças futuras nos requisitos de dados, prefira as “identities”, por causa da flexibilidade que elas já trazem. Isso protege o seu schema contra mudanças futuras.

🔔 ATENÇÃO! REGRA BOBA À VISTA! 🔔

Use IDENTITY!

Em aplicações novas, use colunas identity; use sempre uma coluna identity, a menos que você precise suportar versões antigas do PostgreSQL (lembre-se: as colunas identity chegaram no PostgreSQL v10). Isso deixa o seu código mais fácil de manter, mais limpo e mais portável.

Conclusão

No cenário dinâmico do design de bancos de dados PostgreSQL, a escolha entre “identities” e tipos “serial” para primary keys geradas automaticamente depende da complexidade do schema, das necessidades de desempenho e da adaptabilidade a longo prazo. As “identities” se destacam nos cenários que pedem flexibilidade, clareza e aderência ao padrão, enquanto os tipos “serial” atendem situações simples e voltadas ao desempenho. Alinhando a escolha às particularidades do seu projeto, você consegue montar um schema de banco sólido e otimizado para os seus requisitos. Lembre-se: o objetivo final é encontrar o equilíbrio entre eficiência, clareza e preparo para o futuro ao lidar com primary keys geradas automaticamente no PostgreSQL.

Artigos relacionados sobre PostgreSQL:

Treinamentos

Se você quer dominar o PostgreSQL, a minha empresa oferece alguns treinamentos bem procurados:

Se a sua empresa precisa de um treinamento sob medida, fale com a gente.

Os treinamentos estão disponíveis remotamente e presencialmente.

Outros links interessantes:

Comments