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 / 9829
Accepted
Martin Smith
Martin Smith
Asked: 2011-02-24 09:19:23 +0800 CST2011-02-24 09:19:23 +0800 CST 2011-02-24 09:19:23 +0800 CST

Desempenho de índices não agrupados em heaps versus índices agrupados

  • 772

Este White Paper de 2007 compara o desempenho de instruções individuais de seleção/inserção/exclusão/atualização e seleção de intervalo em uma tabela organizada como um índice clusterizado versus uma tabela organizada como um heap com um índice não clusterizado nas mesmas colunas de chave que o CI tabela.

Geralmente, a opção de índice agrupado teve melhor desempenho nos testes, pois há apenas uma estrutura para manter e porque não há necessidade de pesquisas de favoritos.

Um caso potencialmente interessante não coberto pelo artigo seria uma comparação entre um índice não clusterizado em um heap versus um índice não clusterizado em um índice clusterizado. Nesse caso, eu esperava que o heap pudesse ter um desempenho ainda melhor, pois uma vez no nível de folha NCI, o SQL Server tem um RID para seguir diretamente, em vez de precisar percorrer o índice clusterizado.

Alguém está ciente de testes formais semelhantes que foram realizados nesta área e, em caso afirmativo, quais foram os resultados?

sql-server clustered-index
  • 3 3 respostas
  • 6085 Views

3 respostas

  • Voted
  1. Best Answer
    Filip De Vos
    2011-03-05T14:57:50+08:002011-03-05T14:57:50+08:00

    Para verificar seu pedido criei 2 tabelas seguindo esse esquema:

    • 7,9 milhões de registros representando informações de saldo.
    • um campo de identidade contando de 1 a 7,9 milhões
    • um campo numérico que agrupa os registros em cerca de 500 mil grupos.

    A primeira tabela chamada heapobteve um índice não clusterizado no campo group. A segunda tabela chamada clustobteve um índice clusterizado no campo sequencial chamado keye um índice não clusterizado no campogroup

    Os testes foram executados em um processador I5 M540 com 2 núcleos hyperthreaded, 4Gb de memória e Windows 7 de 64 bits.

    Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64) 
    Apr  2 2010 15:48:46 
    Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)  
    

    Atualização em 9 de março de 2011 : fiz um segundo benchmark mais extenso executando o seguinte código .net e registrando Duration, CPU, Reads, Writes e RowCounts no Sql Server Profiler. (O CommandText usado será mencionado nos resultados.)

    NOTA: CPU e duração são expressos em milissegundos

    • 1000 consultas
    • zero consultas de CPU são eliminadas dos resultados
    • 0 linhas afetadas são eliminadas dos resultados
    int[] idList = new int[] { 6816588, 7086702, 6498815 ... }; // 1000 values here.
    using (var conn = new SqlConnection(@"Data Source=myserver;Initial Catalog=mydb;Integrated Security=SSPI;"))
                {
                    conn.Open();
                    using (var cmd = new SqlCommand())
                    {
                        cmd.Connection = conn;
                        cmd.CommandType = CommandType.Text;
                        cmd.CommandText = "select * from heap where common_key between @id and @id+1000"; 
                        cmd.Parameters.Add("@id", SqlDbType.Int);
                        cmd.Prepare();
                        foreach (int id in idList)
                        {
                            cmd.Parameters[0].Value = id;
    
                            using (var reader = cmd.ExecuteReader())
                            {
                                int count = 0;
                                while (reader.Read())
                                {
                                    count++;
                                }
                                Console.WriteLine(String.Format("key: {0} => {1} rows", id, count));
                            }
                        }
                    }
                }
    

    Fim da atualização em 9 de março de 2011 .

    SELECIONE o desempenho

    Para verificar os números de desempenho, executei as seguintes consultas uma vez na tabela heap e uma vez na tabela cluster:

    select * from heap/clust where group between 5678910 and 5679410
    select * from heap/clust where group between 6234567 and 6234967
    select * from heap/clust where group between 6455429 and 6455729
    select * from heap/clust where group between 6655429 and 6655729
    select * from heap/clust where group between 6955429 and 6955729
    select * from heap/clust where group between 7195542 and 7155729
    

    Os resultados deste benchmark são para heap:

    rows  reads CPU   Elapsed 
    ----- ----- ----- --------
    1503  1510  31ms  309ms
    401   405   15ms  283ms
    2700  2709  0ms   472ms
    0     3     0ms   30ms
    2953  2962  32ms  257ms
    0     0     0ms   0ms
    

    Atualização em 9 de março de 2011 : cmd.CommandText = "select * from heap where group between @id and @id+1000";

    • 721 linhas têm > 0 CPU e afetam mais de 0 linhas
    Counter   Minimum    Maximum Average  Weighted
    --------- ------- ---------- ------- ---------
    RowCounts    1001      69788    6368         -         
    Cpu            15        374      37   0.00754
    Reads        1069      91459    7682   1.20155
    Writes          0          0       0   0.00000
    Duration   0.3716   282.4850 10.3672   0.00180
    

    Fim da atualização em 9 de março de 2011 .


    para a tabela clustos resultados são:

    rows  reads CPU   Elapsed 
    ----- ----- ----- --------
    1503  4827  31ms  327ms
    401   1241  0ms   242ms
    2700  8372  0ms   410ms
    0     3     0ms   0ms
    2953  9060  47ms  213ms
    0     0     0ms   0ms
    

    Atualização em 9 de março de 2011 : cmd.CommandText = "select * from clust where group between @id and @id+1000";

    • 721 linhas têm > 0 CPU e afetam mais de 0 linhas
    Counter   Minimum    Maximum Average  Weighted
    --------- ------- ---------- ------- ---------
    RowCounts    1001      69788    6056         -
    Cpu            15        468      38   0.00782
    Reads        3194     227018   20457   3.37618
    Writes          0          0       0       0.0
    Duration   0.3949   159.6223 11.5699   0.00214
    

    Fim da atualização em 9 de março de 2011 .


    SELECIONE COM JOIN desempenho

    cmd.CommandText = "select * from heap/clust h join keys k on h.group = k.group where h.group between @id and @id+1000";


    Os resultados deste benchmark são para heap:

    873 linhas têm > 0 CPU e afetam mais de 0 linhas

    Counter   Minimum    Maximum Average  Weighted
    --------- ------- ---------- ------- ---------
    RowCounts    1009       4170    1683         -
    Cpu            15         47      18   0.01175
    Reads        2145       5518    2867   1.79246
    Writes          0          0       0   0.00000
    Duration   0.8215   131.9583  1.9095   0.00123
    

    Os resultados deste benchmark são para clust:

    865 linhas têm > 0 CPU e afetam mais de 0 linhas

    Counter   Minimum    Maximum Average  Weighted
    --------- ------- ---------- ------- ---------
    RowCounts    1000       4143    1685         -
    Cpu            15         47      18   0.01193
    Reads        5320      18690    8237   4.97813
    Writes          0          0       0   0.00000
    Duration   0.9699    20.3217  1.7934   0.00109
    

    ATUALIZAR desempenho

    O segundo lote de consultas são instruções de atualização:

    update heap/clust set amount = amount + 0 where group between 5678910 and 5679410
    update heap/clust set amount = amount + 0 where group between 6234567 and 6234967
    update heap/clust set amount = amount + 0 where group between 6455429 and 6455729
    update heap/clust set amount = amount + 0 where group between 6655429 and 6655729
    update heap/clust set amount = amount + 0 where group between 6955429 and 6955729
    update heap/clust set amount = amount + 0 where group between 7195542 and 7155729
    

    os resultados deste benchmark para heap:

    rows  reads CPU   Elapsed 
    ----- ----- ----- -------- 
    1503  3013  31ms  175ms
    401   806   0ms   22ms
    2700  5409  47ms  100ms
    0     3     0ms   0ms
    2953  5915  31ms  88ms
    0     0     0ms   0ms
    

    Atualização em 9 de março de 2011 : cmd.CommandText = "update heap set amount = amount + @id where group between @id and @id+1000";

    • 811 linhas têm > 0 CPU e afetam mais de 0 linhas
    Counter   Minimum    Maximum Average  Weighted
    --------- ------- ---------- ------- ---------
    RowCounts    1001      69788    5598       811         
    Cpu            15        873      56   0.01199
    Reads        2080     167593   11809   2.11217
    Writes          0       1687     121   0.02170
    Duration   0.6705   514.5347 17.2041   0.00344
    

    Fim da atualização em 9 de março de 2011 .


    os resultados deste benchmark para clust:

    rows  reads CPU   Elapsed 
    ----- ----- ----- -------- 
    1503  9126  16ms  35ms
    401   2444  0ms   4ms
    2700  16385 31ms  54ms
    0     3     0ms   0ms 
    2953  17919 31ms  35ms
    0     0     0ms   0ms
    

    Atualização em 9 de março de 2011 : cmd.CommandText = "update clust set amount = amount + @id where group between @id and @id+1000";

    • 853 linhas têm > 0 CPU e afetam mais de 0 linhas
    Counter   Minimum    Maximum Average  Weighted
    --------- ------- ---------- ------- ---------
    RowCounts    1001      69788    5420         -
    Cpu            15        594      50   0.01073
    Reads        6226     432237   33597   6.20450
    Writes          0       1730     110   0.01971
    Duration   0.9134   193.7685  8.2919   0.00155
    

    Fim da atualização em 9 de março de 2011 .


    EXCLUIR referências

    o terceiro lote de consultas que executei são instruções de exclusão

    delete heap/clust where group between 5678910 and 5679410
    delete heap/clust where group between 6234567 and 6234967
    delete heap/clust where group between 6455429 and 6455729
    delete heap/clust where group between 6655429 and 6655729
    delete heap/clust where group between 6955429 and 6955729
    delete heap/clust where group between 7195542 and 7155729
    

    O resultado deste benchmark para heap:

    rows  reads CPU   Elapsed 
    ----- ----- ----- -------- 
    1503  10630 62ms  179ms
    401   2838  0ms   26ms
    2700  19077 47ms  87ms
    0     4     0ms   0ms
    2953  20865 62ms  196ms
    0     4     0ms   9ms
    

    Atualização em 9 de março de 2011 : cmd.CommandText = "delete heap where group between @id and @id+1000";

    • 724 linhas têm > 0 CPU e afetam mais de 0 linhas
    Counter   Minimum    Maximum Average  Weighted
    --------- ------- ---------- ------- ---------
    RowCounts     192      69788    4781         -
    Cpu            15        499      45   0.01247
    Reads         841     307958   20987   4.37880
    Writes          2       1819     127   0.02648
    Duration   0.3775  1534.3383 17.2412   0.00349
    

    Fim da atualização em 9 de março de 2011 .


    o resultado deste benchmark para clust:

    rows  reads CPU   Elapsed 
    ----- ----- ----- -------- 
    1503  9228  16ms  55ms
    401   3681  0ms   50ms
    2700  24644 46ms  79ms
    0     3     0ms   0ms
    2953  26955 47ms  92ms
    0     3     0ms   0ms
    

    Atualização em 9 de março de 2011 :

    cmd.CommandText = "delete clust where group between @id and @id+1000";

    • 751 linhas têm > 0 CPU e afetam mais de 0 linhas
    Counter   Minimum    Maximum Average  Weighted
    --------- ------- ---------- ------- ---------
    RowCounts     144      69788    4648         -
    Cpu            15        764      56   0.01538
    Reads         989     458467   30207   6.48490
    Writes          2       1830     127   0.02694
    Duration   0.2938  2512.1968 24.3714   0.00555
    

    Fim da atualização em 9 de março de 2011 .


    INSERIR benchmarks

    A última parte do benchmark é a execução de instruções de inserção.

    inserir no heap/clust (...) valores (...), (...), (...), (...), (...), (...)


    O resultado deste benchmark para heap:

    rows  reads CPU   Elapsed 
    ----- ----- ----- -------- 
    6     38    0ms   31ms
    

    Atualização em 9 de março de 2011 :

    string str = @"insert into heap (group, currency, year, period, domain_id, mtdAmount, mtdAmount, ytdAmount, amount, ytd_restated, restated, auditDate, auditUser)
                        values";
    
                        for (int x = 0; x < 999; x++)
                        {
                            str += string.Format(@"(@id + {0}, 'EUR', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test'),  ", x);
                        }
                        str += string.Format(@"(@id, 'CAD', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test') ", 1000);
    
                        cmd.CommandText = str;
    
    • 912 instruções têm > 0 CPU
    Counter   Minimum    Maximum Average  Weighted
    --------- ------- ---------- ------- ---------
    RowCounts    1000       1000    1000         -
    Cpu            15       2138      25   0.02500
    Reads        5212       7069    6328   6.32837
    Writes         16         34      22   0.02222
    Duration   1.6336   293.2132  4.4009   0.00440
    

    Fim da atualização em 9 de março de 2011 .


    O resultado deste benchmark para clust:

    rows  reads CPU   Elapsed 
    ----- ----- ----- -------- 
    6     50    0ms   18ms
    

    Atualização em 9 de março de 2011 :

    string str = @"insert into clust (group, currency, year, period, domain_id, mtdAmount, mtdAmount, ytdAmount, amount, ytd_restated, restated, auditDate, auditUser)
                        values";
    
                        for (int x = 0; x < 999; x++)
                        {
                            str += string.Format(@"(@id + {0}, 'EUR', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test'),  ", x);
                        }
                        str += string.Format(@"(@id, 'CAD', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test') ", 1000);
    
                        cmd.CommandText = str;
    
    • 946 instruções têm > 0 CPU
    Counter   Minimum    Maximum Average  Weighted
    --------- ------- ---------- ------- ---------
    RowCounts    1000       1000    1000         -      
    Cpu            15       2403      21   0.02157
    Reads        6810       8997    8412   8.41223
    Writes         16         25      19   0.01942
    Duration   1.5375   268.2571  6.1463   0.00614
    

    Fim da atualização em 9 de março de 2011 .


    Conclusões

    Embora haja mais leituras lógicas acontecendo ao acessar a tabela com o índice clusterizado e não clusterizado (ao usar o índice não clusterizado), os resultados de desempenho são:

    • SELECT statements are comparable
    • UPDATE statements are faster with a clustered index in place
    • DELETE statements are faster with a clustered index in place
    • INSERT statements are faster with a clustered index in place

    Of course my benchmark was very limited on a specific kind of table and with a very limited set of queries, but I think that based on this information we can already start saying that it is virtually always better to create a clustered index on your table.

    Update on 9 Mar 2011:

    As we can see from the added results, the conclusions on the limited tests were not correct in every case.

    Weighted Duration

    The results now indicate that the only statements which benefit from the clustered index are the update statements. The other statements are about 30% slower on the table with clustered index.

    Some additional charts where I plotted the weighted duration per query for heap vs clust. Weighted Duration heap vs clustered for Select

    Weighted Duration heap vs clustered for Join

    Weighted Duration heap vs clustered for Update

    Weighted Duration heap vs clustered for Delete

    As you can see the performance profile for the insert statements is quite interesting. The spikes are caused by a few data points which take a lot longer to complete. Weighted Duration heap vs clustered for Insert

    End of Update on 9 Mar 2011.

    • 41
  2. marc_s
    2011-02-24T09:50:14+08:002011-02-24T09:50:14+08:00

    Como Kimberly Tripp - a Rainha da Indexação - explica muito bem em sua postagem no blog The Clustered Index Debate continua... , ter uma chave de clustering em uma tabela de banco de dados praticamente acelera todas as operações - não apenas SELECT.

    SELECT são geralmente mais lentos em um heap em comparação com uma tabela em cluster, desde que você escolha uma boa chave de cluster - algo como um arquivo INT IDENTITY. Se você usar uma chave de cluster muito ruim, como um GUID ou uma chave composta com muitos componentes de comprimento variável, então, mas somente então, um heap pode ser mais rápido. Mas, nesse caso, você realmente precisa limpar o design do banco de dados em primeiro lugar...

    Portanto, em geral, não acho que haja sentido em uma pilha - escolha uma chave de cluster boa e útil e você deve se beneficiar em todos os aspectos.

    • 12
  3. Martin Smith
    2012-03-16T02:44:37+08:002012-03-16T02:44:37+08:00

    Just happened to come across this article from Joe Chang that addresses this question. Pasted his conclusions below.

    Consider a table for which the indexes have depth 4, so that there is a root level, 2 intermediate levels and the leaf level. The index seek for a single index key (that is, no key lookup) would generate 4 logical IO (LIO). Now consider if a key lookup is required. If the table has a clustered index also of depth 4, each key lookup generates 4 LIO. If the table were a heap, each key lookup generates 1 LIO. In actuality, the key lookup to a heap is about 20-30% less expensive than a key lookup to a clustered index, not anywhere close to the 4:1 LIO ratio.

    • 7

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

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

    • 4 respostas
  • Marko Smith

    Como você mostra o SQL em execução em um banco de dados Oracle?

    • 2 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

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

    • 10 respostas
  • Marko Smith

    Posso ver Consultas Históricas executadas em um banco de dados SQL Server?

    • 6 respostas
  • Marko Smith

    Como uso currval() no PostgreSQL para obter o último id inserido?

    • 10 respostas
  • Marko Smith

    Como executar o psql no Mac OS X?

    • 11 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
  • Marko Smith

    Passando parâmetros de array para um procedimento armazenado

    • 12 respostas
  • Martin Hope
    Manuel Leduc Restrição exclusiva de várias colunas do PostgreSQL e valores NULL 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler Quando uma chave primária deve ser declarada sem cluster? 2011-11-11 13:31:59 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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
  • Martin Hope
    BrunoLM Guid vs INT - Qual é melhor como chave primária? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick Como posso otimizar um mysqldump de um banco de dados grande? 2011-01-04 13:13:48 +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