Uau, a resposta correta "Não permita NULLs quando você não precisar, porque eles prejudicam o desempenho" é de alguma forma a última resposta classificada. Vou votá-lo e elaborar. Quando um RDBMS permite NULLs para uma coluna não esparsa, essa coluna é adicionada a um bitmap que rastreia se o valor é NULL para cada linha individual. Portanto, adicionando capacidade NULL a uma coluna em uma tabela em que todas as colunas não permitem NULLs, você aumenta o espaço de armazenamento necessário para salvar a tabela. Além disso, você está exigindo que o RDBMS leia e grave no bitmap, prejudicando o desempenho em todas as operações.
Além disso, em vários casos, permitir NULLs quebrará 3NF. Embora eu não seja um defensor da 3NF como muitos de meus colegas, considere o seguinte cenário:
Na tabela Pessoa, há uma coluna chamada DateOfDeath, que é anulável. Se uma pessoa morreu, ela será preenchida com o DateOfDeath, caso contrário, será deixado NULL. Há também uma coluna de bits não anulável chamada IsAlive. Esta coluna é definida como 1 se a pessoa estiver viva e 0 se a pessoa estiver morta. A grande maioria dos procedimentos armazenados usa a coluna IsAlive, eles se importam apenas se uma pessoa estiver viva, não seu DateOfDeath.
No entanto, a coluna IsAlive interrompe a normalização do banco de dados, porque é completamente derivável de DateOfDeath. Mas como o IsAlive está conectado à maioria dos SPs, a solução direta é tornar o DateOfDeath não nulo e atribuir um valor padrão à coluna no caso de a pessoa ainda estar viva. Os poucos SPs que usam DateOfDeath podem ser reescritos para verificar a coluna IsAlive e honrar o DateOfDeath apenas se a pessoa não estiver viva. Novamente, como a maioria dos SPs se preocupa apenas com o IsAlive (um pouco) e não com o DateOfDeath (uma data), esse padrão acelera consideravelmente o acesso.
Um script T-SQL útil para localizar colunas anuláveis sem NULLs em todos os esquemas é:
select 'IF NOT EXISTS (SELECT 1 FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' WHERE ' + QUOTENAME(c.name) + ' IS NULL)
AND (SELECT COUNT(*) FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ') > 1 PRINT ''' + s.name + '.' + t.name + '.' + REPLACE(c.name, '''', '''''') + ''''
from sys.columns c
inner join sys.tables t ON c.object_id = t.object_id
inner join sys.schemas s ON s.schema_id = t.schema_id
where c.is_nullable = 1 AND c.is_computed = 0
order by s.name, t.name, c.name;
Se você executar isso em uma cópia do banco de dados de produção, poderá encontrar as colunas desenvolvedores marcadas como permitindo NULLs que não possuem NULLs na prática. A grande maioria deles pode ser marcada como NOT NULL, aumentando assim o desempenho e diminuindo o espaço de armazenamento.
Pode não ser possível eliminar todos os NULLs em todas as tabelas e ainda ter um design limpo, mas há uma vantagem considerável na eliminação do maior número possível de NULLs. O otimizador trabalha muito mais rápido com essas informações e, se você puder eliminar todos os NULLs em uma tabela, poderá recuperar uma quantidade considerável de espaço de armazenamento.
Eu sei que desempenho não é algo que os DBAs pensam muito, mas você só pode gastar uma quantidade limitada de memória e potência do processador em uma solução, em algum momento você precisará começar a pensar em design lógico e físico .
Observe também que isso é apenas para RDBMSes verdadeiros e estou baseando a parte técnica das minhas respostas no SQL Server. O T-SQL listado para encontrar colunas anuláveis sem nulos também é do SQL Server.