Ideia central

Boas práticas no SQL Server cobrem desde modelagem de dados e escrita de T-SQL até configuração de instância e segurança. Seguir essas práticas reduz retrabalho, melhora performance e evita problemas difíceis de diagnosticar em produção.

Modelagem e Design

Chaves primárias:

  • Prefira colunas INT IDENTITY ou BIGINT IDENTITY como PK: menores, ordenadas, eficientes como chave de índice clustered
  • Evite GUIDs (UNIQUEIDENTIFIER) como PKs clustered, pois causam fragmentação massiva por serem aleatórios. Se precisar de GUID, use NEWSEQUENTIALID() ou coloque a PK como não-clustered
-- Bom: INT IDENTITY como PK clustered
CREATE TABLE pedidos (
    id         INT IDENTITY(1,1) PRIMARY KEY,
    cliente_id INT NOT NULL,
    data       DATETIME2 NOT NULL DEFAULT SYSDATETIME()
);
 
-- Cuidado: GUID como clustered PK gera fragmentação
-- Prefira newsequentialid() se GUID for obrigatório
CREATE TABLE items (
    id UNIQUEIDENTIFIER DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
    ...
);

Tipos de dados:

  • Use DATETIME2 em vez de DATETIME, mais preciso, com menor custo de armazenamento e mais range de datas
  • Use NVARCHAR apenas quando Unicode for necessário; VARCHAR é mais eficiente para dados ASCII
  • Defina tamanhos realistas: VARCHAR(MAX) no lugar errado impede uso de índices
  • Evite FLOAT/REAL para valores monetários; use DECIMAL(18,2) ou MONEY

Constraints:

  • Sempre defina NOT NULL explicitamente quando o campo não pode ser nulo
  • Use constraints CHECK para validar domínios de dados no banco
  • Nomeie suas constraints para facilitar troubleshooting de erros de violação
ALTER TABLE pedidos ADD CONSTRAINT chk_status
    CHECK (status IN ('pendente', 'aprovado', 'cancelado'));

Escrita de T-SQL

Evite SELECT *: especifique sempre as colunas necessárias: reduz I/O, evita quebrar código quando colunas são adicionadas/removidas e permite ao otimizador usar index covering

-- Ruim
SELECT * FROM pedidos WHERE cliente_id = 100;
 
-- Bom
SELECT id, data, total, status FROM pedidos WHERE cliente_id = 100;

Evite funções em colunas filtradas (SARGability): funções aplicadas na coluna do WHERE impedem uso de índices

-- Ruim: não usa índice em data_pedido
WHERE YEAR(data_pedido) = 2026
 
-- Bom: SARGable, usa índice
WHERE data_pedido >= '2026-01-01' AND data_pedido < '2027-01-01'
 
-- Ruim
WHERE UPPER(nome) = 'LOGAN'
 
-- Bom: use collation case-insensitive ou ajuste os dados
WHERE nome = 'Logan' -- se collation for CI (Case Insensitive)

Prefira JOINs explícitos: nunca use sintaxe de join implícita (FROM a, b WHERE a.id = b.id)

Use transações com cuidado:

  • Mantenha transações o mais curtas possível, pois transações longas bloqueiam outros processos
  • Sempre trate erros com TRY/CATCH e faça ROLLBACK em caso de exceção
BEGIN TRY
    BEGIN TRANSACTION;
        UPDATE contas SET saldo = saldo - 500 WHERE id = 1;
        UPDATE contas SET saldo = saldo + 500 WHERE id = 2;
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
    THROW; -- re-lança o erro
END CATCH;

SET NOCOUNT ON em stored procedures: evita enviar mensagens de “N rows affected” para cada statement, reduzindo o tráfego de rede

CREATE PROCEDURE dbo.usp_processar_pedido @pedido_id INT
AS
BEGIN
    SET NOCOUNT ON;
    -- código aqui
END;

Indexação

  • Crie índices baseado nos padrões reais de acesso (queries do sistema), não em teoria
  • Covering index: inclua colunas adicionais com INCLUDE para queries específicas
-- Covering index: busca por status, retorna id/data sem precisar buscar na tabela
CREATE INDEX idx_pedidos_status
ON dbo.pedidos (status)
INCLUDE (id, data, total);
  • Evite over-indexing, pois cada índice tem custo de manutenção em INSERT/UPDATE/DELETE
  • Revise índices não usados: sys.dm_db_index_usage_stats

Segurança

Princípio do menor privilégio: aplicações nunca devem usar sa ou roles como sysadmin/db_owner. Crie logins específicos com permissões mínimas necessárias.

Autenticação: prefira Windows Authentication (Kerberos/NTLM) em ambientes corporativos, mais seguro que SQL Authentication. Em containers/cloud, SQL Auth com senhas fortes é aceitável.

Senhas: SQL Logins devem ter CHECK_POLICY = ON para aplicar política de senha do Windows.

Dados sensíveis:

  • Use Dynamic Data Masking para ocultar dados de usuários sem privilégio
  • Use Transparent Data Encryption (TDE) para criptografar arquivos em repouso

Configurações de instância

-- Verificar configurações importantes
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
 
-- Max memory: NUNCA deixe em 0 (usa toda a RAM do servidor)
-- Deixe ao menos 4GB livres para o OS
EXEC sp_configure 'max server memory (MB)', 28672; -- ex: 28 GB
RECONFIGURE;
 
-- Cost threshold for parallelism: padrão é 5 (muito baixo)
-- Valores entre 25-50 são mais adequados para evitar paralelismo desnecessário
EXEC sp_configure 'cost threshold for parallelism', 35;
RECONFIGURE;
 
-- Max degree of parallelism: evite deixar no padrão 0 (usa todos os cores)
-- Regra geral: MAXDOP = número de cores por NUMA node, máximo 8
EXEC sp_configure 'max degree of parallelism', 4;
RECONFIGURE;

Convenção de nomenclatura

Tabelas:      PascalCase, singular (Pedido, ClientePJ)
Colunas:      PascalCase ou snake_case (seja consistente)
SPs:          usp_ + verbo + substantivo (usp_ProcessarPedido)
Functions:    ufn_ prefixo
Views:        v_ prefixo
Índices:      idx_Tabela_Coluna(s)
PKs:          pk_Tabela
FKs:          fk_TabelaFilha_TabelaPai
CHECKs:       chk_Tabela_Descricao

Conexões

Referências