Индексирование и управление таблицами для запросов с COUNT (DISTINCT ...) - PullRequest
0 голосов
/ 02 ноября 2019

У меня есть несколько больших (~ миллиард строк, ~ 100 ГБ) архивных таблиц с журналами поведения клиентов для аналитических целей (еще нет хранилища, в процессе разработки).

Каждый заполняется один раз в день из таблицы ежедневных журналов и содержит данные за текущий год.

  • вне ежедневных вставок эти таблицы никогда не изменяются, выбираются только из

  • ежедневные журналы располагаются в порядке столбца servertime, который может работать как первичный ключ, однако он не используется ни для какого запроса, кроме ежедневной вставки,

  • все запросы ограничены диапазонами столбца datetime. Эти два столбца примерно одинаковы примерно в 90% времени, в остальное время они могут быть разнесены даже на несколько дней,
  • servertime отмечает при отправке пакета журналов (поэтому они обычно сортируются по возрастанию в плоских файлах), а datetime - это фактическое время создания журнала, которое может оставаться в кэше несколько дней.

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

SELECT 
    CAST(datetime as date), 
    element, 
    COUNT(DISTINCT client_id), 
    COUNT(DISTINCT session_id), 
    COUNT(*)
FROM dbo.pageviews
WHERE DATETIME >= ''
   AND DATETIME < ''
GROUP BY CAST(DATETIME as date), element

В других случаях нам приходится тянуть все журналы для данногоclient_id или session_id в течение заданного периода.

У нас была некоторая устаревшая индексация (некластеризованная с несколькими включенными столбцами, с индексами, кратными размеру таблиц).

IЯ пытаюсь немного улучшить ситуацию, пока мы ждем склад, поэтому я начал вносить некоторые базовые изменения.

Вопрос 1:

Я добавил кластерd индексировать по столбцу datetime (для справки по запросам) и некластеризовать по servetime (для облегчения ежедневных вставок). Это правильно или должно быть наоборот?

Вопрос 2:

Если бы мы разбили таблицы, скажем, на ежемесячные порции и выполнили запросы по отношению кСМОТРИТЕ со всеми их как UNION ALL и datetime как кластеризованный индекс, было бы полезно, если бы мы часто вычисляли COUNT(distinct X) по периодам, которые охватывали бы несколько таких таблиц?

Любые другие исправления, которые могли бы помочь управлять этимв краткосрочной перспективе?

Контрольный пример: Я проверил запрос, как указано выше, с трехмесячным периодом с различной индексацией и получил следующие результаты:

  • нет индексов вообще - ~ 38 минут
  • кластеризованный индекс для datetime - ~ 34 минуты
  • некластеризованный индекс для datetime с include для всех соответствующих столбцов - ~ 34минут

РЕДАКТИРОВАТЬ: Дополнительная информация:

  • В последнее время 33% времени servertime больше datetime, datetime такжепод влиянием изменений часового пояса, летом он падает до 18% (GMT + 2 / GMT + 1)

  • Существует небольшое, но не незначительное количество журналов, загруженных с datetime намного, намного раньше, чем текущая временная метка, иногда даже месяцы. Это приемлемо с нашей точки зрения отчетности, но может оказать существенное влияние на кластеризованный индекс более datetime, если он продолжит добавлять новые строки назад.

Ответы [ 2 ]

2 голосов
/ 02 ноября 2019

У вас сложная проблема;это, вероятно, слишком широк. Но у него есть простое решение - разбиение на столбец datetime, поскольку этот столбец используется для запросов к таблицам. Я просто хочу указать на некоторые проблемы высокого уровня.

Тем не менее, более простой столбец для разбиения - это servertime - это позволит вам просто поменять местами разделы. Однако это происходит за счет усложнения запросов. Если вы знаете, что значение datetime всегда находится в разделе, скажем, через три дня после его значения, вы можете выполнить эту работу.

Некоторые базы данных ограничивают количество «открытых» разделов, которые вы можете вставитьв. Я не думаю, что SQL Server имеет это ограничение.

Однако у вас будет другая проблема. Результаты могут меняться со временем. Итак, если вы рассчитываете количество whatevers на 2019-10-31. Затем вы можете получить разные значения в 2019-11-01, а затем в 2019-11-02 и т. Д., Поскольку данные накапливаются.

Это может быть большой проблемой, если вы используете данные для чего-то, чтодолжен быть статичным, например, финансовая отчетность. Вы можете включить произвольное ограничение в запросы. Примерно так:

select *
from . . .
where partition_date = '2019-10-31' and
      abs(datediff(day, servertime, datetime)) < 7;

Обратите внимание, что я добавил псевдостолбец partition_date, просто чтобы понять, что используется для разбиения. Вы можете использовать datetime непосредственно для этого.

То есть данные поступают в течение недели. Вы не указали, если servertime больше datetime. Обратите внимание, что это может быть возможно, даже если вы думаете, что это не из-за смещения времени на компьютерах и, возможно, из-за проблем с часовым поясом.

1 голос
/ 02 ноября 2019

Это правильно, что вы создали кластерный индекс для столбца «datetime». Если в столбце servetime не производится регулярный поиск, то некластеризованный индекс не очень помогает.
Здесь вам нужно и может значительно повысить производительность разбиение вашей таблицы. Он логически разделяет данные ваших таблиц, поэтому вам не нужно изменять какие-либо из существующих запросов, а извлекайте выгоду из разделения данных.
Разделение - это сложная концепция. Вы можете найти полезную информацию здесь .

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