Uma característica de qualquer banco de dados é a existência de dados que não podem duplicar. Geralmente estes dados identificam algo como o CPF para identificar uma pessoa ou o CNPJ para identificar uma empresa ou o número de série para identificar um produto e assim por diante.
Porém, quando se fala em banco de dados, qual a melhor maneira de implementar esta necessidade?
Antigamente, nos tempos do COBOL, era necessário fazer uma varredura no arquivo de dados para verificar se um determinado código já existia. Com os RDBMS’s, isso ficou mais fácil.
Ao criar uma tabela, o analista pode especificar a unicidade do campo. O Próprio sistema já irá garantir a unicidade.
As duas maneiras de fazer isso é através da criação de uma constraint única ou através da criação de um índice e, por conta destas duas opções, sempre volta a pergunta: Qual das duas é melhor em termos de desempenho do banco de dados.
vamos demonstrar de forma objetiva qual a vantagem das duas técnicas, para isso vamos criar uma tabela conforme abaixo:
Create table PlzTeste (PlzTesteID int identity(1,1) not null ,CodigoUnico varchar(6) not null ,DataInclusao datetime not null ,Constraint PlzTeste_PK primary key (PlzTesteID));
Agora vamos inserir um volume mínimo de dados para que os Índices ou Constraints façam algum efeito nos testes, conforme script abaixo:
ATENÇÃO: Este processo levou cerca de 15 minutos, gerou 1.000.000 registros que ocuparam 30 MB
Declare @Nivel1 TinyInt = 0; Declare @Nivel2 TinyInt = 0; Declare @Nivel3 TinyInt = 0; Declare @Nivel4 TinyInt = 0; Declare @Nivel5 TinyInt = 0; Declare @Nivel6 TinyInt = 0; Declare @Padrao TinyInt = 9; WHILE @Nivel1 <= @Padrao BEGIN WHILE @Nivel2 <= @Padrao BEGIN WHILE @Nivel3 <= @Padrao BEGIN WHILE @Nivel4 <= @Padrao BEGIN WHILE @Nivel5 <= @Padrao BEGIN WHILE @Nivel6 <= @Padrao BEGIN INSERT INTO PlzTeste VALUES (Cast(@Nivel1 AS CHAR(1))+Cast(@Nivel2 AS CHAR(1))+ Cast(@Nivel3 AS CHAR(1))+Cast(@Nivel4 AS CHAR(1))+ Cast(@Nivel5 AS CHAR(1))+Cast(@Nivel6 AS CHAR(1)) ,GetDate()); set @Nivel6 = @Nivel6 + 1; END; set @Nivel6 = 0; set @Nivel5 = @Nivel5 + 1; END; set @Nivel5 = 0; set @Nivel4 = @Nivel4 + 1; END; set @Nivel4 = 0; set @Nivel3 = @Nivel3 + 1; END; set @Nivel3 = 0; set @Nivel2 = @Nivel2 + 1; END; set @Nivel2 = 0; set @Nivel1 = @Nivel1 + 1; END;
Carregada a base de dados, vamos fazer uma consulta para que possamos estabelecer um parâmetro e ser utilizado para comparação:
select count(*) from PlzTeste where codigounico = '486451';
Observe o plano de acesso sem o Índice e sem a Constraint é:
Agora vamos criar a constraint única e ver o novo plano de execução:
alter table PlzTeste add constraint PlzTeste_UK unique (CodigoUnico);
Agora veja o plano de acesso com a Constraint:
Agora vamos eliminar a Constraint e criar o Índice único:
alter table PlzTeste drop constraint PlzTeste_UK; create unique index PlzTestes_U01 on PlzTeste (CodigoUnico);
Vejamos como fica o plano de acesso com o índice único:
Comparação entre Constraint e Índice
Observe que os planos de acessos para o acesso feito através do índice e através da Constraint são exatamente os mesmos, não houve variação nos custos (especialmente no custo de I/O) do acesso.
Portanto, criando um Índice ou criando uma Constraint o desempenho do acesso será o mesmo.
Porém, a utilização do Índice possui alguns benefícios quando aplicados em situações específicas, mas isto será explicado em outro artigo.
[Crédito da Imagem: Unicidade do Campo – ShutterStock]