Столкновения CHECKSUM () в SQL Server 2005 - PullRequest
9 голосов
/ 22 июня 2009

У меня есть таблица из 5 651 744 строк с первичным ключом из 6 столбцов (int x 3, smallint, varchar (39), varchar (2)). Я рассчитываю повысить производительность с помощью этой таблицы и другой таблицы, которая использует этот первичный ключ плюс добавленный дополнительный столбец, но имеет 37 млн ​​строк.

В ожидании добавления столбца для создания хеш-ключа я провел анализ и обнаружил 18 733 столкновения.

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

Это примерно вдвое хуже с BINARY_CHECKSUM()

Это кажется слишком высоким (0,33%), учитывая меньшее относительное количество места назначения, которое я покрываю? И если коллизии настолько велики, есть ли преимущество в том, чтобы сначала присоединяться к этому изготовленному ключу в соединениях за счет дополнительных 4 байтов на строку, учитывая, что вам все еще нужно соединяться с обычными столбцами для обработки случайных коллизий?

Ответы [ 5 ]

7 голосов
/ 23 июня 2009

Я не вижу, откуда добавление контрольной суммы даст вам что-либо с таким уровнем коллизий. Даже 1 коллизия - это слишком много, так как это приведет к неправильному соединению данных. Если вы не можете гарантировать, что присоединитесь к правильной записи, бессмысленно, если это повышает производительность, но портит целостность данных. Это, похоже, финансовые данные, поэтому вам лучше быть уверенным, что ваши запросы не дадут плохих результатов. На самом деле вы можете в конечном итоге списать или зачислить неверные счета, если возникнут какие-либо коллизии.

Если вы пойдете этим путем, Марк прав, что вы должны, если это возможно, выполнить предварительные вычисления (добавление вычисления, которое должно происходить с каждой записью в таблицах с многомиллионными записями, вряд ли повысит производительность в моем опыте). Возможно, если вы можете сделать предварительно вычисленный столбец (и вам понадобятся триггеры, чтобы поддерживать его актуальность), вам может не потребоваться присоединиться ко всем шести другим столбцам, чтобы избежать коллизий. Тогда, возможно, вы могли улучшить производительность. Все, что вы можете сделать, это проверить свою теорию. Но будьте уверены, что у вас нет столкновений.

Рассматривали ли вы использование суррогатного ключа, а затем уникальный индекс для шести полей естественного ключа? Тогда вы можете присоединиться к суррогатному ключу и, вероятно, это немного улучшит производительность. Невозможно объединить шесть столбцов (один - varchar) вместо одного суррогатного ключа. По размеру данных, я понимаю, что это может быть сложнее реорганизовать, чем в непроизводственной системе, но на самом деле может стоить простоя, чтобы навсегда решить постоянные проблемы с производительностью. Только вы можете сказать, насколько сложным было бы это изменение и как трудно было бы изменить все sps или запросы для лучшего объединения. Тем не менее, это может быть целесообразно попробовать.

6 голосов
/ 06 июля 2009

До сих пор я видел, что многие люди приукрашивают то, что CHECKSUM имеет массу коллизий, по признанию Microsoft . Это даже хуже, чем MD5, у которого есть значительная доля значимых столкновений.

Если вы хотите получить хеш-столбец, рассмотрите возможность использования HASHBYTES с указанным SHA1. SHA1 имеет гораздо менее значимые коллизии, чем MD5 или CHECKSUM. Следовательно, CHECKSUM никогда не следует использовать для определения уникальности строки, а, скорее, это быстрая проверка точности двух значений. Следовательно, ваша частота столкновений должна составлять 0% при HASHBYTES, если только у вас нет повторяющихся строк (что, будучи PK, никогда не должно происходить).

Имейте в виду, что HASHBYTES будет усекать все, что больше 8000 байт, но ваш PK намного меньше этого (все объединено), поэтому у вас не должно быть никаких проблем.

2 голосов
/ 22 июня 2009

Если ваша контрольная сумма уменьшит до 0,33% данных, я бы сказал, что она работает нормально ... особенно если вы используете этот столбец в сочетании с другими (проиндексированными) столбцами.

Конечно, чтобы быть эффективным в качестве индекса, вы, вероятно, захотите вычислить и сохранить это значение при вставке / обновлении данных с некластеризованным индексом.

Конечно, обычный охватывающий индекс по рассматриваемым столбцам может работать так же хорошо или лучше ...

1 голос
/ 24 июня 2009

ЕСЛИ ваш PRIMARY KEY кластеризован, то каждый созданный вами индекс будет содержать PRIMARY KEY.

Присоединение к хешированному значению будет использовать следующие шаги:

  1. Найдите хешированное значение в ключе индекса.
    • Найдите значение PRIMARY KEY в данных индекса
    • Используйте Clustered Index Seek, чтобы найти строку PRIMARY KEY в таблице

Для присоединения к PRIMARY KEY будет использоваться только шаг 3.

SQL Server, однако, достаточно умен, чтобы принять это во внимание, и если вы присоединитесь так:

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

, он просто не будет использовать индекс для HASH_KEY, вместо этого он будет использовать одиночные Clustered Index Seek и Filter, чтобы убедиться, что значения хеша совпадают (и они всегда будут).

Резюме : просто присоединитесь к PRIMARY KEY.

Используя вторичный индекс, вы сначала должны выполнить бесполезный поиск HASH_KEY, а затем все равно должны присоединиться к PRIMARY KEY.

1 голос
/ 24 июня 2009

Если ваши запросы являются выборочными, а кластеризованный индекс таблицы строк является узким или отсутствует, то некластеризованный индекс контрольной суммы в таблице строк должен обеспечить хорошую производительность.

После применения любых критериев к таблице заголовков она будет использовать контрольную сумму для поиска индекса по некластеризованному индексу. Вам все еще нужно включить FK в объединение, но критерии объединения без контрольной суммы будут применяться после индексации поиска после поиска закладки. Очень эффективно.

Вы хотите оптимизировать поиск по индексу. Контрольная сумма уже очень избирательная. Добавление FK увеличило бы размер индекса и соответствующий ввод-вывод, и не помогло бы, если бы в нем не было достаточно других полей, чтобы вообще избежать поиска закладок.

Поскольку некластеризованный индекс будет содержать ключи кластеризации или указатель кучи, вам потребуется либо a) небольшой ключ кластеризации (например, столбец с идентификатором int - 4-байтовый указатель), либо b) кластерный индекс вообще не будет указатель байта).

Если ваши запросы не являются выборочными, или если кластеризованный индекс таблицы строк огромен (вся таблица минус несколько столбцов), тогда я не знаю, поможет ли контрольная сумма (возможно, более быстрая навигация по индексу?). В любом случае вы захотите сделать его кластеризованным или охватывающим индексом, и если таблица заголовков не кластеризована в первую очередь по контрольной сумме, будет много сортировки.

Если вы можете позволить себе затраты на хранение и индексацию, возможно, вам подойдут несколько покрывающих индексов - заголовок и подробности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...