Eu tenho um aplicativo (os dados são armazenados no PostgreSQL), onde a maioria dos campos nas tabelas nem sempre é nula, mas o esquema para essas tabelas não impõe isso. Por exemplo, veja esta tabela falsa:
CREATE TABLE "tbl" (
"id" serial,
"name" varchar(40),
"num" int,
"time" timestamp
PRIMARY KEY ("id"),
UNIQUE ("id")
);
Além disso name
, num
, time
não são explicitamente indicado como NOT NULL
, na realidade, eles são, porque a aplicação acontece no lado de aplicação.
Meu sentimento é que ele deve ser alterado, mas o contraponto é que o nível do aplicativo garante que os valores nulos não possam aparecer aqui e ninguém mais modifique manualmente a tabela.
Minha pergunta é : Quais são os benefícios (desempenho, armazenamento, consistência, outra coisa) e desvantagens (supondo que eu já verifiquei que não há nulos presentes no momento e, pela lógica de negócios, não deve haver nulos) definindo um NOT NULL
restrição explícita ?
Temos um bom processo de revisão de código e uma documentação razoavelmente boa; portanto, a possibilidade de alguém novo cometer algo que rompa essa restrição não é realmente suficiente para justificar a alteração.
Esta não é uma decisão minha, por isso é exatamente por que estou procurando outras justificativas. Na minha opinião, se algo não puder ser nulo e um banco de dados permitir que você especifique que algo não é nulo - basta fazê-lo. Especialmente se a mudança for super simples.
fonte
NOT NULL
restrições não têm efeito direto no tamanho do armazenamento. Obviamente, com todas as colunas sendo definidasNOT NULL
, não pode haver um bitmap nulo para começar. Por outro lado: o tamanho do armazenamento é geralmente muito menor se você usar NULL em vez de valores "vazios" ou fictícios para colunas sem valor real, porque o bitmap nulo é comparativamente muito menor (exceto casos de borda raros).Respostas:
O que acontece quando um novo programador chega e precisa escrever um aplicativo nesse banco de dados? Eles não sabem que o campo x deve ser
NOT NULL
.Outro programa pode assumir que todos os campos x são
NOT NULL
para executar contagens, digamos, mas alguns agora sãoNULL
por causa do novo programa, levando a erros inconsistentes e difíceis de rastrear.IMHO é sempre melhor aplicar regras de integridade de dados o mais próximo possível dos dados, ou seja, no banco de dados. Dessa forma, novos aplicativos e / ou programadores não podem atrapalhar seus dados.
Programadores, aplicativos, linguagens e estruturas vêm e vão. Dados e bancos de dados tendem a persistir. O banco de dados é sua última linha de defesa contra dados inconsistentes e potencialmente errôneos.
Aproveite ao máximo os mecanismos de imposição de restrições de integridade do seu banco de dados, mesmo à custa do desempenho. Um sistema lento que produz resultados corretos é infinitamente superior a um sistema rápido que erra as coisas!
fonte
IMHO it is always best to enforce data integrity rules as near to the data as possible
na verdade, é o mesmo que o instinto sobre o qual escrevi. E é exatamente por isso que estou procurando justificativas reais. Temos uma revisão de código em vigor e boa documentação, portanto, as preocupações com um novo desenvolvedor que não sabe algo não são suficientes para justificar a alteração.REAL PROGRAMMERS
leem toda (ou mesmo alguma) da documentação antes de ficarem presos em um projeto em que eles têm um prazo apertado?Como já citado por outros nos comentários, adicionar
NOT NULL
à especificação da sua tabela pode melhorar de maneira significativa o desempenho de suas consultas (além das boas razões metodológicas declaradas em outra resposta).O motivo é que o otimizador de consulta, sabendo que uma coluna não pode ter um
NULL
valor, pode excluir testes especiais para esses valores, como no casoNOT IN
vs.NOT EXISTS
Você pode ver, por exemplo, este blog , onde é mostrado que não declarar um campoNOT NULL
(quando a tabela sempre contém valores não nulos) com uma determinada consulta aumenta o tempo de execução de 500%. O resultado é mostrado para o SQL Server, mas um comportamento semelhante pode estar presente em outros DBMSs relacionais, como o seu (para não mencionar o fato de que seu banco de dados pode ser portado para outros sistemas). Uma regra geral que você pode assumir é que, quando mais informações estão disponíveis para o otimizador de consultas, planos de acesso mais eficientes podem ser produzidos.fonte
NOT NULL
por várias razões, sem argumento sobre isso. Mas o link para o blog sobre o SQL Server não é aplicável ao Postgres e não prova nenhuma das implicações de desempenho mencionadas. Não estou dizendo que não há, mas eu adoraria ver evidências reais .not in
colunas anuláveis é diferente, portanto, deve haver alguma diferença no plano entre as duas.Implicações espaciais
As implicações espaciais são discutidas neste post por @Erwin Brandstetter
Em resumo, você salvará um
totalColumns - 8
bit arredondado para o byte mais próximo (ouMAXALIGN
), se o seu banco de dados tiverNOT NULL
Implicações de desempenho
No entanto, neste post no SE de @Erwin Brandstetter , ele diz
O @Renzo tem uma resposta que fala sobre as implicações de desempenho - eu assumiria que nada disso é aplicável ao PostgreSQL . Eu não consigo encontrar nada que substancia nenhum de que como sendo relevantes para PostgreSQL. Quaisquer que sejam os ciclos salvos, não podem ser quantificados nem na consulta mais rudimentar.
Além disso, fiz alguns testes para verificar se os índices NULL eram cada vez mais rápidos e não consegui comprovar isso. Você pode encontrar esse encadeamento extremamente útil de Scott Marlowe nas listas de discussão que falam sobre o planejador de consultas na 9.1 ser capaz de usar índice parcial em cláusulas WHERE diferentes. Eu testei isso executando o seguinte
Agora eu criei os índices,
Nos dois casos, o planejador conseguiu usar o índice ao selecionar
= 10
e usar uma verificação seq ao procurar por NULL ou 0, respectivamente. Ambos os índices parciais tinham o mesmo tamanho. E, índices completos (não mostrados) tinham o mesmo tamanho. Seguindo a mesma metodologia, carreguei a tabela com uma sequência de1..1e5
, e o valor nulo / 0, e outra sequência de1..1e5
. Ambos os métodos foram capazes de encontrar o nulo / 0 com um índice cobrindo a tabela inteira.TLDR; Sumário
Não posso substanciar nada de uma maneira ou de outra na maioria das preocupações de desempenho que achei que valia a pena testar por incluir inadequações do planejador. O benefício de usar null para salvar ram é real. O espaço em disco economizado por não usar nulo é insignificante, e isso é um exagero em tabelas com uma
NULLABLE
coluna ou menos de 8 colunas. Nesses casos, não há espaço em disco salvo.fonte