AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 342253
Accepted
J. Mini
J. Mini
Asked: 2024-09-10 01:57:45 +0800 CST2024-09-10 01:57:45 +0800 CST 2024-09-10 01:57:45 +0800 CST

Existe algum benefício em declarar um índice que contém uma chave primária como único?

  • 772

Suponha que eu tenha uma tabela com muitas colunas com as quais não me importo, mas duas com as quais me importo: Primarye Secondary. Há uma chave primária agrupada em Primary.

CREATE TABLE [dbo].[OnlyTwoGoodColumnsButManyBad]
(
    [Primary] INT PRIMARY KEY CLUSTERED,
    [Secondary] NVARCHAR(500) NOT NULL,
    [Evil1] NVARCHAR(MAX),
    [Evil2] NVARCHAR(MAX),
    [Evil3] NVARCHAR(MAX),
    [Evil4] NVARCHAR(MAX),
    [Evil5] NVARCHAR(MAX)
);

Como não me importo com nenhuma das outras colunas, decido que quero este índice:

CREATE NONCLUSTERED INDEX [IX_Primary_Secondary]
ON [dbo].[OnlyTwoGoodColumnsButManyBad]
(
    [Primary],
    [Secondary]
);

Dado que a lista de chaves deste índice contém a chave primária, não há dúvidas de que a lista de chaves é única. Assim, estou tentado a torná-la UNIQUE.

CREATE UNIQUE NONCLUSTERED INDEX [UIX_Primary_Secondary]
ON [dbo].[OnlyTwoGoodColumnsButManyBad]
(
    [Primary],
    [Secondary]
);

Mas isso tem algum benefício? E o que dizer do mesmo caso exato, mas com o Secondarycomo a chave de índice principal seguido por Primary?

sql-server
  • 2 2 respostas
  • 414 Views

2 respostas

  • Voted
  1. Best Answer
    Josh Darnell
    2024-09-10T19:04:04+08:002024-09-10T19:04:04+08:00

    Singularidade e Desempenho

    Argumentos PARA declarar unicidade

    Normalmente, é melhor fornecer mais informações ao otimizador do que menos. Se você sabe que um índice é único, é melhor declará-lo dessa forma. Isso pode ajudar o otimizador, bem como fornecer clareza sobre seus dados para pessoas reais que estão olhando para as definições de esquema.

    Isso pode ter um impacto direto no desempenho. Veja o artigo de Paul White Enforcing Uniqueness for Performance para um exemplo.

    Argumentos CONTRA a declaração de unicidade

    Quanto às especificidades desta questão, tentei adaptar seu cenário de índice não clusterizado à demonstração no artigo de Paul, e parece que buscas singleton são usadas, independentemente de o índice não clusterizado ser declarado exclusivo ou não. Incluí o código de demonstração modificado no final desta resposta.

    Com base nisso, parece que o otimizador é capaz de inferir exclusividade pela inclusão da chave UNIQUE do índice clusterizado. Esse conceito é mais completamente confirmado e desenvolvido neste Q&A: Devo marcar um índice composto como exclusivo se ele contiver a chave primária?

    Há também certos cenários em que um índice UNIQUE pode causar sobrecarga de desempenho, então não há uma resposta mágica aqui, infelizmente. Veja estes artigos para leitura relacionada:

    • Cuidado com leituras furtivas com índices exclusivos
    • SQL Server, buscas e pesquisa binária

    Ordem das Chaves de Índice

    Em relação à ordenação das colunas, isso realmente depende dos tipos de consultas que serão executadas contra essa tabela. E essa é mais ou menos a orientação "geral" sobre índices que entra em jogo aqui. Você geralmente quer a coluna "mais seletiva" primeiro.

    Se as consultas normalmente incluem um valor para "Primário" como um filtro (ou condição de junção), então esse é um candidato ideal - você pode buscar diretamente na linha certa. Se as consultas normalmente fornecem apenas um valor para "Secundário", então Primário não é uma boa chave de índice líder - você teria que escanear cada linha na tabela. Nesse caso, Secundário é uma escolha melhor para liderar o índice.


    Código de demonstração

    Veja abaixo o código que usei. Novamente, ele foi adaptado (possivelmente incorretamente, já que sou apenas um humilde desenvolvedor web) do artigo de Paul:

    SET STATISTICS TIME, IO ON;
    
    CREATE TABLE [dbo].[OnlyTwoGoodColumnsButManyBad]
    (
        [Primary] INT PRIMARY KEY CLUSTERED,
        [Secondary] NVARCHAR(500) NOT NULL,
        [Evil1] NVARCHAR(MAX),
        [Evil2] NVARCHAR(MAX),
        [Evil3] NVARCHAR(MAX),
        [Evil4] NVARCHAR(MAX),
        [Evil5] NVARCHAR(MAX)
    );
    
    INSERT dbo.OnlyTwoGoodColumnsButManyBad
        WITH (TABLOCKX)
        ([Primary], Secondary)
    SELECT TOP (5000000)
        [Primary] = 
            ROW_NUMBER() OVER (
                ORDER BY @@SPID),
      Secondary = 'Garbage'
    FROM 
        master.sys.columns AS C
        CROSS JOIN master.sys.columns AS c2
        CROSS JOIN master.sys.columns AS c3
    ORDER BY
        [Primary];
    
    CREATE NONCLUSTERED INDEX [IX_Primary_Secondary]
    ON [dbo].[OnlyTwoGoodColumnsButManyBad]
    (
        [Primary],
        [Secondary]
    );
    
    CREATE UNIQUE NONCLUSTERED INDEX [UIX_Primary_Secondary]
    ON [dbo].[OnlyTwoGoodColumnsButManyBad]
    (
        [Primary],
        [Secondary]
    );
    
    SELECT 
        COUNT_BIG(*)
    FROM dbo.[OnlyTwoGoodColumnsButManyBad] AS ST 
        WITH (TABLOCK, INDEX ([IX_Primary_Secondary]))
    JOIN dbo.[OnlyTwoGoodColumnsButManyBad] AS ST2
        WITH (TABLOCK, INDEX ([IX_Primary_Secondary]))
        ON ST2.[Primary] = ST.[Primary] AND ST2.[Secondary] = ST.[Secondary]
    OPTION (MAXDOP 1, LOOP JOIN, FORCE ORDER);
    
    /*
    Table 'OnlyTwoGoodColumnsButManyBad'. 
    Scan count 1, logical reads 15329888
    CPU time = 5000 ms,  elapsed time = 5312 ms.
    */
    
    SELECT 
        COUNT_BIG(*)
    FROM dbo.[OnlyTwoGoodColumnsButManyBad] AS ST 
        WITH (TABLOCK, INDEX ([UIX_Primary_Secondary]))
    JOIN dbo.[OnlyTwoGoodColumnsButManyBad] AS ST2
        WITH (TABLOCK, INDEX ([UIX_Primary_Secondary]))
        ON ST2.[Primary] = ST.[Primary] AND ST2.[Secondary] = ST.[Secondary]
    OPTION (MAXDOP 1, LOOP JOIN, FORCE ORDER);
    /*
    Table 'OnlyTwoGoodColumnsButManyBad'. 
    Scan count 1, logical reads 15329888
    CPU time = 4984 ms,  elapsed time = 5283 ms.
    */
    
    • 10
  2. sepupic
    2024-09-10T21:37:47+08:002024-09-10T21:37:47+08:00

    Há outro benefício em declarar o índice como único.

    Cada um non unique indexé sempre maior que o similar unique index. Isso ocorre porque no caso de índice não clusterizado não exclusivo, o rowID(RID ou chave de índice clusterizado) também é armazenado em níveis de índice não folha .

    O índice não clusterizado não exclusivo (seu caso) sempre tem o clustered index keypresente em todos os níveis de índice, enquanto um índice exclusivo similar não precisa dele em seus níveis não-folha, então quanto maior for sua chave de índice clusterizado, maior será o tamanho do seu non uniqueíndice não clusterizado.

    Não consegui encontrar a documentação oficial, mas aqui está uma explicação sobre isso: Por que os níveis raiz e intermediário de índices NÃO exclusivos e NÃO agrupados armazenam adicionalmente o ID da linha?

    Ok, aqui está minha reprodução:

    select n, replicate('0', 200) + cast(n as varchar(10)) as n1
    into dbo.nums
    from fleetxs.dbo.nums
    
    alter table nums add constraint PK_nums primary key clustered(n)
    create index ix_n1 on dbo.nums(n1) 
    
    DBCC IND (test, nums, 2)
    
    --187341
    --187342
    
    DBCC TRACEON(3604)
    DBCC PAGE(test, 1, 187341, 3) 
    

    Acabei de criar uma tabela a partir da minha tabela de trabalho dbo.Nums que contém números inteiros de 1 a 1000000, coloquei a coluna única n como ela está na coluna n da minha nova tabela e criei outra coluna replicate('0', 200) + cast(n as varchar(10)) as n1, aqui a replicação é usada apenas para o propósito de uma coluna grande o suficiente para obter não apenas raiz + folha, mas também 1 nível intermediário.

    O índice nesta coluna não é único, mas o conteúdo é único por definição.

    Então obtenho minhas páginas de índice com DBCC IND:

    insira a descrição da imagem aqui

    Pego 2 páginas que representam o nível intermediário e raiz e as examino:

    1. nível intermediário insira a descrição da imagem aqui

    2. nível raiz insira a descrição da imagem aqui

    Ambos têm a coluna de índice clusterizado na como parte da chave. Os valores na coluna n1 são únicos, no entanto.

    • 3

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve