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 / 284029
Accepted
Dirk Boer
Dirk Boer
Asked: 2021-01-27 09:13:37 +0800 CST2021-01-27 09:13:37 +0800 CST 2021-01-27 09:13:37 +0800 CST

Economize desempenho com grande atualização no índice com coluna incluída

  • 772
Points
------------------
PK  QuestionId  int (+30.000.000 distinct values)
PK  EventId     int (large batches where 80.000 rows have the same EventId)
    Value       smallint

A tabela tem cerca de 40 milhões de linhas e apresenta problemas de desempenho.

Existem duas dúvidas principais:

Em QuestionId :

  • cerca de 30 milhões de QuestionIdvalores diferentes (muita variação)
  • muitas consultas durante os horários de pico (vários milhares por minuto)

Em EventId :

  • haverá atualizações em lote de +150.000 linhas where EventId=Xpara definir Value=NULLdurante os momentos de muito movimento.

Portanto, meu primeiro pensamento para obter o melhor desempenho foi fazer EventId,QuestionIdo ClusteredIndex para que a atualização em lote possa encontrar facilmente todos os EventId próximos uns dos outros e atualizar diretamente os valores.

Meu segundo pensamento foi adicionar um índice com uma QuestionIdcoluna incluída Value para que ele possa ler o valor diretamente do índice ( EventIdé irrelevante neste caso).

Mas então pensei: o Índice Agrupado importaria? Como o Valor da coluna Incluído do Índice também precisa ser atualizado durante a atualização do lote.

  • Embora não negocie o desempenho da consulta - é possível obter a atualização do lote rapidamente (alguns segundos) ou tenho que aceitar que esse processo sempre será lento sem atualizar o hardware.
  • Quaisquer outros pensamentos qual seria a melhor maneira de definir o ClusteredIndex / Indexes?

Eu sei que, em teoria, eu deveria testar tudo e medi-lo, mas o site está ativo e é muito usado.

Sou um desenvolvedor solo e não tenho recursos para contratar alguém. Quaisquer suposições e pensamentos estimados sobre isso seriam realmente úteis, pois isso já me dá a direção certa!

sql-server performance
  • 1 1 respostas
  • 494 Views

1 respostas

  • Voted
  1. Best Answer
    bbaird
    2021-01-27T09:45:17+08:002021-01-27T09:45:17+08:00

    Portanto, se seu caminho de acesso principal for por pergunta , o índice clusterizado exclusivo que fizer mais sentido será (QuestionId, EventId).

    Adicionar um segundo índice EventIdpode não ser útil, pois o índice pode não ser seletivo o suficiente e o mecanismo de consulta decidirá que é mais rápido ler a tabela inteira em vez de fazer muito trabalho para ler uma grande parte dela.

    Como alternativa, se você sempre consulta com base total ou parcialmente em EventId, o índice clusterizado de (EventId,Questionid)é mais adequado e tem o benefício adicional de fazer suas atualizações baseadas em EventIdexigir menos E/S para serem concluídas.

    Eu não incluiria Valueem um índice adicional, pois isso basicamente copiará a tabela inteira (apenas agrupada em colunas diferentes) e suas atualizações levarão ainda mais tempo, pois Valuedevem ser mantidas sincronizadas no índice clusterizado e no índice adicional.

    Em um certo ponto, não há almoço grátis, e a solução correta é provavelmente escolher o índice clusterizado com a coluna principal que suporta a maioria dos casos de uso e, em seguida, adicionar RAM/CPU/armazenamento mais rápido para lidar com casos em que a tabela inteira (ou grande pedaços dele) devem ser lidos ou gravados. Com 40 milhões de linhas e uma tabela tão estreita, não consigo imaginar isso sendo algo que mais RAM não resolveria.

    Dependendo da sua edição do SQL Server, você também pode verificar se a compactação de página reduziria significativamente o tamanho da tabela, pois isso reduziria o número de leituras/gravações no disco (a sobrecarga adicional da CPU é compensada por menos operações de disco). Meu palpite no seu caso é que não, mas é um trabalho olhando.

    Então, se eu entendi corretamente (com o conhecimento atual), seu pressentimento seria o Índice Agrupado QuestionId,EventIde, em seguida, um Índice normalEventId para a atualização do lote?

    Somente se o uso principal for retornar específico QuestionIdssem considerar EventId. Você pode experimentar o índice adicional em EventId, mas pode descobrir que ele não está sendo usado com frequência (ou de todo) para atualizações (ou as atualizações ainda demoram mais do que você gostaria), dependendo de como os EventIds são distribuídos por meio de seus dados em relação para QuestionId.

    Você também precisa determinar o que é mais importante para você em geral - selecionar o desempenho ou atualizar o desempenho. Se a atualização for o ponto problemático, (EventId,QuestionId)sem dúvida será a melhor escolha. Dado o número de valores exclusivos para QuestionId, adicionar um índice nessa coluna pode ser útil para o SELECTdesempenho, mas isso dependerá de como QuestionIdé distribuído e de quantos você está procurando por vez.

    Manter as estatísticas atualizadas será crucial em ambos os casos.

    Um exemplo extremamente simples (por uma questão de completude):

    Digamos que temos um DBMS que mantém um índice clusterizado e armazena 4 linhas por página. Temos uma tabela com uma chave primária de (QuestionId, EventId)e uma coluna adicional, Value.

    Se criarmos o índice clusterizado como (QuestionId, EventId), os dados em nosso DBMS imaginário são (grosseiramente falando) armazenados assim:

    Page | QuestionId | EventId | Value
    -----------------------------------
    A    | 1          | 2       | ...
    A    | 1          | 3       | ...
    A    | 1          | 6       | ...
    A    | 1          | 7       | ...
    B    | 1          | 8       | ...
    B    | 1          | 10      | ...
    B    | 1          | 11      | ...
    B    | 2          | 2       | ...
    C    | 3          | 2       | ...
    C    | 4          | 1       | ...
    C    | 5          | 6       | ...
    C    | 5          | 7       | ...
    D    | 6          | 1       | ...
    D    | 7          | 2       | ...
    D    | 7          | 6       | ...
    D    | 7          | 8       | ...
    

    Portanto, se eu precisar realizar uma operação baseada em QuestionId, o mecanismo não precisará ler mais páginas do que o necessário.

    No entanto, se eu precisar realizar uma operação baseada em EventId, terei que ler a tabela inteira (varredura de índice clusterizado), a menos que eu adicione um índice adicional, que ficará assim (e exigirá quatro páginas):

    EventId | QuestionId
    --------------------
    1       | 4
    1       | 6
    2       | 1
    2       | 2
    2       | 3
    2       | 7
    3       | 1
    6       | 1
    6       | 5
    6       | 7
    7       | 1
    7       | 5
    8       | 1
    8       | 7
    10      | 1
    11      | 1
    

    Este índice pode ser seletivo para alguns EventIds, mas no caso extremo ( EventId = 2) a tabela inteira ainda precisaria ser lida, e para alguns casos ( EventId = 6) nosso otimizador pode decidir que pesquisar o índice e ler a tabela é mais caro do que apenas ler o índice inteiro tabela.

    Se, em vez disso, agruparmos em EventId, QuestionIdnossa tabela se parece com isso:

    Page | EventId | QuestionId | Value
    -----------------------------------
    A    | 1        | 4         | ...
    A    | 1        | 6         | ...
    A    | 2        | 1         | ...
    A    | 2        | 2         | ...
    B    | 2        | 3         | ...
    B    | 2        | 7         | ...
    B    | 3        | 1         | ...
    B    | 6        | 1         | ...
    C    | 6        | 5         | ...
    C    | 6        | 7         | ...
    C    | 7        | 1         | ...
    C    | 7        | 5         | ...
    D    | 8        | 1         | ...
    D    | 8        | 7         | ...
    D    | 10       | 1         | ...
    D    | 11       | 1         | ...
    

    Qualquer operação baseada em EventIdlerá apenas as partes necessárias da tabela e, como nossa primeira instância, qualquer operação baseada em QuestionIdexigirá uma varredura sem um índice adicional. Se criarmos um índice em QuestionId, o índice será:

    QuestionId | EventId
    --------------------
    1          | 2
    1          | 3
    1          | 6
    1          | 7
    1          | 8
    1          | 10
    1          | 11
    2          | 2
    3          | 2
    4          | 1
    5          | 6
    5          | 7
    6          | 1
    7          | 2
    7          | 6
    7          | 8
    

    Assim como no primeiro exemplo, este índice será mais útil para algumas questões e menos útil para outras. Pois QuestionId = 1o otimizador provavelmente dirá que o custo de ler metade do índice e procurar metade da tabela não vale o custo e apenas lerá a tabela inteira em vez de utilizar o índice.

    Se incluirmos Valueno índice, agora temos que alterar a tabela E o índice dentro da mesma transação. Na melhor das hipóteses, isso duplica o trabalho para qualquer operação. Na pior das hipóteses, isso requer que toda a tabela ou índice (que é apenas uma cópia da tabela) seja lido e possivelmente bloqueado.

    Agora, com seus dados reais, é possível adicionar um índice adicional QuestionIdou EventIdfornecer muitos benefícios. Mas não vai resolver todos os problemas, e pode não valer a pena a sobrecarga imposta em inserções/atualizações/exclusões.

    • 8

relate perguntas

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

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

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

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