Вопрос

У меня есть таблица из 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%), учитывая меньший относительный объем целевого пространства, которое я покрываю?И если количество коллизий так велико, есть ли выгода в объединении по этому изготовленному ключу первым в joins за счет дополнительных 4 байт на строку, учитывая, что вам все равно придется объединяться по обычным столбцам, чтобы обрабатывать случайные коллизии?

Это было полезно?

Решение

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

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

ЕСЛИ ваш 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top