В качестве упрощенного примера, предположим, у меня есть такая таблица:
seq | value
----+------
102 | 11954
211 | 43292
278 | 19222
499 | 3843
Таблица может содержать сотни миллионов записей, и мне нужно часто делать такие запросы:
SELECT sum(value) WHERE seq > $a and seq < $b
Даже если seq
он проиндексирован, типичная реализация базы данных будет проходить по каждой строке для вычисления суммы в лучшем случае O(n)
, где n
размер диапазона.
Есть ли база данных, которая может сделать это эффективно, как в O(log(n))
запросе?
Я наткнулся на структуру данных, которая называется деревом сегментов, как описано здесь . Также иногда упоминается как дерево диапазонов или дерево интервалов, хотя все эти имена часто описываются как слегка отличающийся вариант структуры данных.
Однако я не сталкивался ни с одной базой данных, которая реализует такую структуру данных. Реализовать его с нуля легко для структуры в памяти, но он становится сложным, если его необходимо сохранить или он слишком велик, чтобы поместиться в памяти. Если есть эффективный шаблон для реализации этого поверх существующей базы данных, это также может помочь.
Примечание: это таблица не только для добавления, поэтому такое решение, как сохранение накопленной суммы, в этом случае не будет работать.
Ответы:
Использование SQL Server ColumnStore indexes
Ну, ладно, только один - кластерный индекс CS.
Если вы хотите прочитать об оборудовании, на котором я это сделал, зайдите сюда . Полное раскрытие, я написал этот пост в блоге на сайте компании, в которой я работаю.
На тесте!
Вот некоторый общий код для создания довольно большой таблицы. То же предупреждение, что и у Эвана, для сборки и индексации может потребоваться некоторое время.
Ну, Эван побеждает за простоту, но я говорил об этом раньше.
Вот определение индекса. Ла и Ди и Дах.
Глядя на количество, каждый Id имеет довольно равномерное распределение:
Результаты:
...
С каждым идентификатором, имеющим ~ 5,005,005 строк, мы можем рассмотреть довольно маленький диапазон идентификаторов, чтобы получить сумму в 10 миллионов строк.
Результат:
Профиль запроса:
Для удовольствия, большая агрегация:
Результаты:
Профиль запроса:
Надеюсь это поможет!
источник
PostgreSQL с индексом BRIN
Это не правда. По крайней мере, ни одна приличная база данных не сделает этого. PostgreSQL поддерживает создание индексов BRIN для таблиц такого типа. Индексы BRIN очень малы и могут поместиться в оперативной памяти даже на таких больших столах. Сотни миллионов строк - это не ничто.
Здесь 300 миллионов строк определены так же, как вы их заказали. Предупреждение: на его создание может уйти много времени (время: 336057,880 мс + 95121,809 мс для индекса).
И сейчас...
1,4 секунды для агрегирования / суммирования 5 889 135 строк в заданном диапазоне.
Несмотря на то, что таблица составляет 10 ГБ, индекс BRIN составляет 304 КБ.
Даже быстрее
Если это все еще недостаточно быстро, вы можете кэшировать агрегаты по 100 тыс. Строк.
Теперь вам нужно будет только использовать
2(1e5-1)
строки brin и aggregate, а не 300 миллионов или что-то еще.аппаратные средства
Lenovo x230, i5-3230M, 16 ГБ оперативной памяти, 1 ТБ Samsung 840 SSD.
источник
O(n)
, возможноO(sqrt(n))
. Зависит от того, как вы будете определять интервалы, которые будут использоваться при материализации.