Pergunta

Eu tenho uma tabela de 5,651,744 linhas, com uma chave primária feita de 6 colunas (int x 3, smallint, varchar (39), varchar (2)). Eu estou olhando para melhorar o desempenho com esta tabela e outra mesa que compartilha essa chave primária e uma coluna adicional acrescentado, mas tem linhas 37m.

Em antecipação de adicionar uma coluna para criar a chave de hash, eu fiz uma análise e encontrou 18,733 colisões.

SELECT  SUM(CT)
FROM    (
         SELECT HASH_KEY
               ,COUNT(*) AS CT
         FROM   (
                 SELECT CHECKSUM(DATA_DT_ID, BANK_NUM, COST_CTR_NUM,
                                 GL_ACCT_NUM, ACCT_NUM, APPN_CD) AS HASH_KEY
                 FROM   CUST_ACCT_PRFTBLT
                ) AS X
         GROUP BY HASH_KEY
         HAVING COUNT(*) > 1
        ) AS Y

SELECT  COUNT(*)
FROM    CUST_ACCT_PRFTBLT

É cerca de duas vezes tão ruim com BINARY_CHECKSUM()

Isto parece muito alta (0,33%), dada a quantidade relativa menor do espaço de destino Eu estou cobrindo? E se as colisões são grandes, há um benefício em se juntar nesta chave fabricado pela primeira vez em une para o custo dos extra de 4 bytes por linha, uma vez que você ainda tem que se juntar nas colunas regulares para lidar com a colisão ocasional?

Foi útil?

Solução

Não vejo onde a adição de uma soma de verificação, poderá ir qualquer coisa com esse nível de collisons. Mesmo uma colisão é demais, uma vez que faria com que você se juntar aos dados errados. Se você não pode garantir a juntar-se ao registro correto, é inútil se ele melhora o desempenho, mas messes com a integridade dos dados. Esta parece ser dados financeiros, então é melhor ser realmente certeza de que suas consultas não retornará resultados ruins. Você poderia realmente acabar débito ou crédito das contas erradas se existem colisões.

Se você percorrer esse caminho, Marc é certo que você deve, se possível pré-compute (Adicionando um cálculo que tem que acontecer para cada registro na multimilionárias tabelas recorde não é susceptível de melhorar o desempenho na minha experiência). Possivelmente se você pode fazer a coluna de pré-computados (e você vai precisar gatilhos para mantê-lo up-date), então você pode não precisar de se juntar a todos os seis outras colunas para garantir que não haja colisões. Então, possivelmente, você pode ter desempenho Imporved. Tudo o que você pode fazer é testar a sua teoria. Mas estar muito certo de que você não tem nenhum colisões.

Você considerou usando uma chave substituta e, em seguida, um índice exclusivo nos seis campos de chave naturais em vez? Então você poderia juntar-se na chave substituta e provável que iria melhorar o desempenho de um bom bocado. Não pode ser eficiente para se juntar em seis colunas (um VARCHAR) em vez de uma chave substituta. Eu percebo a partir do tamanho dos dados, isso pode ser mais difícil de refactor do que em um sistema não-produção, mas realmente pode valer a pena o tempo para baixo para permananently corrigir problemas de desempenho persistentes. Só você pode dizer o quão complexa uma mudança que seria e como seria difícil de mudar todos os sps ou consultas para uma melhor aderir. No entanto, pode ser viável para tentar.

Outras dicas

O que eu vi um monte de gente passando por cima até agora é que CHECKSUM tem uma tonelada de colisões, por da Microsoft própria admissão . É ainda pior do que MD5, que tem seu quinhão de colisões significativas.

Se você estiver olhando para começar uma coluna de hash, considere o uso HASHBYTES com SHA1 especificado. SHA1 tem muito menos colisões significativos do que MD5 ou CHECKSUM. Portanto, CHECKSUM nunca deve ser usado para determinar se uma linha é único, mas sim, é uma verificação rápida sobre a fidelidade de dois valores. Portanto, a sua taxa de colisão deve ser de 0% com HASHBYTES, a menos que você tem linhas duplicadas (que, sendo um PK, nunca deve acontecer).

Tenha em mente que HASHBYTES irá truncar qualquer coisa maior do que 8000 bytes, mas o seu PK é muito menos do que isso (todos concatenadas), então você não deve ter nenhum problema.

Se a sua soma de verificação recebe-lo para baixo a 0,33% dos dados, então eu diria que ele está funcionando bem ... especialmente se você usar esta coluna em combinação com outras colunas (indexados).

Claro que, para ser eficaz como um índice que você provavelmente vai querer calcular e armazenar este valor quando inserir / actualização de dados, com um índice não agrupado.

Claro, um índice abrangendo regular ao longo das colunas em questão podem fazer tão bem ou melhor ...

Se suas consultas são seletivos e o índice da tabela linha agrupado é estreito ou inexistente, em seguida, um índice não agrupado na soma de verificação na tabela a linha deve proporcionar um bom desempenho.

Depois de aplicar qualquer critério está presente à mesa de cabeçalho, ele usará a soma de verificação para realizar uma busca de índice sobre o índice não agrupado. Você ainda precisa incluir os FKs na juntar-se, mas a não verificação juntar critérios serão aplicados pós-busca de índice, pesquisa de pós-marcador. Muito eficiente.

Você deseja otimizar para a busca de índice. A soma de verificação já é altamente selectiva. Adicionando os FKs aumentaria o tamanho do índice e correspondente I / O, e não ajuda a menos que incluiu suficientes outros campos para evitar o marcador pesquisa completamente.

Uma vez que o índice não agrupado irá conter as chaves de agrupamento ou ponteiro da área, você quer tanto a) uma pequena chave de cluster (por exemplo, uma coluna de identidade int - 4 ponteiro byte) ou b) não índice agrupado em tudo (8 byte ponteiro).

Se as consultas não são selectivas, ou se o índice da tabela linha agrupado é enorme (a tabela inteira menos algumas colunas), então eu não sei se a soma de verificação ajudaria (navegação índice mais rápido, talvez?). Em qualquer caso, você gostaria de torná-lo um tanto ordenação cluster ou cobrindo índice, e se a tabela de cabeçalho não é agrupado na soma de verificação em primeiro lugar, haverá.

Se você pode pagar os custos de armazenamento e indexação, alguns índices de cobertura - cabeçalho e detalhe -. Pode ser o caminho a percorrer

Se o seu PRIMARY KEY está em cluster, em seguida, cada índice que você criar irá conter este PRIMARY KEY.

Unir em um valor hash vai usar esses passos seguintes:

  1. Localize o valor hash na chave de índice
    • Localize o valor PRIMARY KEY nos dados de índice
    • Use Clustered Index Seek para localizar a linha PRIMARY KEY na tabela

Unir em um PRIMARY KEY vai usar apenas o 3 passo.

SQL Server, no entanto, é bastante inteligente para levar isso em conta, e se você irá juntar-se assim:

SELECT  *
FROM    main_table mt
JOIN    CUST_ACCT_PRFTBLT cap
ON      cap.HASH_KEY = mt.HASH_KEY
        AND cap.DATA_DT_ID = mt.DATA_DT_ID
        AND …
WHERE   mt.some_col = @filter_value

, ele só não vai usar o índice em HASH_KEY, em vez disso, ele vai usar um único Clustered Index Seek e uma Filter para garantir que o jogo valores de hash (e eles sempre será).

Resumo :. Basta juntar na PRIMARY KEY

Usando um índice secundário, primeiro você precisa fazer uma pesquisa HASH_KEY inútil, e depois ainda precisa participar na PRIMARY KEY.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top