"Секционирование без границ" Ильдар Мусин (postgres...
TRANSCRIPT
Пример секционирования
id title city1 Велосипед Москва2 Вафельница Санкт-Петербург3 Фотоаппарат Москва4 Контрабас Санкт-Петербург
id title city1 Велосипед Москва3 Фотоаппарат Москва
id title city2 Вафельница Санкт-Петербург4 Контрабас Санкт-Петербург
items
items_msc items_spb
Виды секционирования
Январь
Февраль
Март
Апрель
RANGE
h1
h2
h3
h4
HASH
УфаЧелябинскПермь
СамараСаратов
ВладивостокХабаровск
LIST
Преимущества секционирования
● Рост производительности при условии, что наиболее часто используемые данные находятся в небольшом числе секций.
● Использование последовательного доступа к небольшим секциям вместо индекса или случайного доступа к одной большой таблице.
● Управление большими объемами данных. ● Редко используемые данные могут быть вынесены на более дешевые и медленные носители.
Когда нужно секционировать?
● Эмпирическое правило: размер таблицы превышает размер физической памяти.
● Таблица содержит исторические данные, а новые записи добавляются в последнюю секцию.
● Содержимое таблицы должно быть распределено между дисками или серверами.
Виды секционирования в PostgreSQL
● RANGE CHECK(dt_created >= '2015-01-01' AND dt_created < '2016-01-01')
● LIST CHECK(city IN (‘Уфа’, ‘Оренбург’, ‘Челябинск’))
● HASH (?) CHECK( id % 10 = 0) … CHECK( id % 10 = 9)
SELECT * FROM my_table WHERE id = 5 AND (id % 10) = (5 % 10)
Проблемы
● Полный перебор при поиске подходящих секций (constraint exclusion)
● Нет встроенной поддержки HASH-секционирования
● Ручное управление секциями
Решение
Определить структуры данных, над которыми можно выполнять эффективный поиск
RANGE • бинарный поиск в сортированном массиве • поиск в бинарном дереве
HASH, LIST • хеш-таблица
O(log2N)
≈ O(1)
Используемые средства
Hook-функции — лазейки, используемые для внедрения в код СУБД: • planner_hook • set_rel_pathlist_hook
Path — прототип планов. Для каждой таблицы, используемой в запросе, строятся всевозможные способы обхода, из которых выбирается лучший. На его основе строится узел плана.
ordersid integer
dt_created timestamp
customer_id integer
city_id integer
orders_1 orders_2 orders_3
[2016-01-01; 2016-02-01)
…
[2016-02-01; 2016-03-01) [2016-03-01; 2016-04-01)
Cache
OID Partitioning info
431287
431290
431295
431299partitioning type RANGE
attribute dt_create
attribute type timestamp
children ■■■■■■■■■
Cache
partitioning type RANGE
attribute dt_create
attribute type timestamp
children ■■■■■■■■■
min 2016-01-01 2016-02-01 2016-03-01 2016-04-01
max 2016-02-01 2016-03-01 2016-04-01 2016-05-01
child orders_1 orders_2 orders_3 orders_4
Дерево выражений
OR
AND
>=
const:2016-01-01
var:dt_created
<
const:2016-02-15
=
const:2016-03-15
var:dt_created
SELECT * FROM ordersWHERE (dt_created >= ‘2016-01-01’ AND dt_created <= ‘2016-02-15’) OR (dt_created = ‘2016-03-15’ AND city_id=15)
AND
=
const:15
var:city_id
var:dt_created
Дерево выражений
OR
AND
>=
const:2016-01-01
var:dt_created
<
const:2016-02-15
=
const:2016-03-15
var:dt_created
SELECT * FROM ordersWHERE (dt_created >= ‘2016-01-01’ AND dt_created <= ‘2016-02-15’) OR (dt_created = ‘2016-03-15’ AND city_id=15)
AND
=
const:15
var:city_id
var:dt_created
Дерево выражений
OR
AND
>=
const:2016-01-01
var:dt_created
<
const:2016-02-15
=
const:2016-03-15
var:dt_created
SELECT * FROM ordersWHERE (dt_created >= ‘2016-01-01’ AND dt_created <= ‘2016-02-15’) OR (dt_created = ‘2016-03-15’ AND city_id=15)
AND
=
const:15
var:city_id
var:dt_created
Поиск RANGE-секции
Ищем секцию, содержащую CONST
KEY OP CONST
OP
[0; pos] [pos; pos] [pos; ∞)
<, <= >, >=
=
бинарный поиск
pos — позиция в массиве children
Обработка булевых операторов
Вычисляем EXPR1, Вычисляем EXPR2
EXPR1 BOOL_OP EXPR2
BOOL_OP
Пересечение Объединение
AND OR
0 1 2 3
min 2016-01-01 2016-02-01 2016-03-01 2016-04-01
max 2016-02-01 2016-03-01 2016-04-01 2016-05-01
child orders_1 orders_2 orders_3 orders_4
Пример
OR
AND
dt_created >= ‘2016-01-15’ dt_created < ‘2016-03-01’ dt_created = ‘2016-04-01’
0 1 2 3
min 2016-01-01 2016-02-01 2016-03-01 2016-04-01
max 2016-02-01 2016-03-01 2016-04-01 2016-05-01
child orders_1 orders_2 orders_3 orders_4
Пример
OR
AND
dt_created >= ‘2016-01-15’ dt_created < ‘2016-03-01’ dt_created = ‘2016-04-01’
T T T T
0 1 2 3
min 2016-01-01 2016-02-01 2016-03-01 2016-04-01
max 2016-02-01 2016-03-01 2016-04-01 2016-05-01
child orders_1 orders_2 orders_3 orders_4
Пример
OR
AND
dt_created >= ‘2016-01-15’ dt_created < ‘2016-03-01’ dt_created = ‘2016-04-01’
T T T T T T F F
0 1 2 3
min 2016-01-01 2016-02-01 2016-03-01 2016-04-01
max 2016-02-01 2016-03-01 2016-04-01 2016-05-01
child orders_1 orders_2 orders_3 orders_4
Пример
OR
AND
dt_created >= ‘2016-01-15’ dt_created < ‘2016-03-01’ dt_created = ‘2016-04-01’
T T T T T T F F F F F T
0 1 2 3
min 2016-01-01 2016-02-01 2016-03-01 2016-04-01
max 2016-02-01 2016-03-01 2016-04-01 2016-05-01
child orders_1 orders_2 orders_3 orders_4
Пример
OR
AND
dt_created >= ‘2016-01-15’ dt_created < ‘2016-03-01’ dt_created = ‘2016-04-01’
T T T T T T F F F F F T
T T F F
0 1 2 3
min 2016-01-01 2016-02-01 2016-03-01 2016-04-01
max 2016-02-01 2016-03-01 2016-04-01 2016-05-01
child orders_1 orders_2 orders_3 orders_4
Пример
OR
AND
dt_created >= ‘2016-01-15’ dt_created < ‘2016-03-01’ dt_created = ‘2016-04-01’
T T T T T T F F F F F T
T T F F
T T F T
0 1 2 3
min 2016-01-01 2016-02-01 2016-03-01 2016-04-01
max 2016-02-01 2016-03-01 2016-04-01 2016-05-01
child orders_1 orders_2 orders_3 orders_4
Пример
OR
AND
dt_created >= ‘2016-01-15’ dt_created < ‘2016-03-01’ dt_created = ‘2016-04-01’
P T T T T T F F F F F P
P T F F
P T F P
0 1 2 3
P T F P
Plan:
orders_4
dt_created >= ‘2016-01-15’ dt_created = ‘2016-04-01’full scan
orders_2orders_1
HASH секционирование
OID Partitioning info
431287
431290
431295
431299partitioning type HASH
attribute city_id
attribute type integer
children ■■■■■■■■■
HASH секционирование
partitioning type HASH
attribute city_id
attribute type integer
children ■■■■■■■■■
child orders_1 orders_2 orders_3 orders_4
Дерево выражений
OR
=
const: 5
SELECT * FROM orders WHERE city_id=5 OR city_id=10
=
const: 10var: city_idvar: city_id
Дерево выражений
OR
=
const: 5
SELECT * FROM orders WHERE city_id=5 OR city_id=10
=
const: 10var: city_idvar: city_id
Поиск HASH-секции
KEY OP CONST
OP это оператор равенства?
Вычислить hash от CONST
да нет
[hash; hash] [0; ∞)
hash — позиция в массиве children
Расширение pg_pathman
✓ Оптимизированный механизм построения планов для секционированных таблиц
✓ Функции для управления секциями ✓ Триггеры на вставку
Roadmap
‣ Оптимизация NestedLoop JOIN-ов ‣ LIST-секционирование ‣ HASH-секционирование по нецелочисленным атрибутам
Эксперимент для HASH
Время планирования в зависимости от количества секций в разбиении
Таблица: CREATE TABLE hash_test(id INTEGER);
Количество созданных секций: 2, 4, 8, 16, 32, 64, 128, 512, 1024, 2048
Количество запросов: 10000 на каждой конфигурации
EXPLAIN ANALYZE SELECT * FROM hash_testWHERE id = 10 AND (id%<N> = 10%<N>);(где <N> - количество секций)
Эксперимент для RANGE
Время планирования в зависимости от количества секций в разбиении
Таблица: CREATE TABLE range_test(id INTEGER);
Количество созданных секций: 2, 4, 8, 16, 32, 64, 128, 512, 1024, 2048
Количество запросов: 10000 на каждой конфигурации
EXPLAIN ANALYZE SELECT * FROM range_testWHERE id = 10;
Эксперимент для RANGE
Время планирования в зависимости от количества секций в плане
Таблица: CREATE TABLE range_test(
id INTEGER,dt TIMESTAMP);
Количество созданных секций: 1095
Количество секций, попадающих в план: от 1 до 1095
www.postgrespro.ru
Спасибо за внимание!
Контакты: [email protected] +7 929 929 6075
github.com/postgrespro/pg_pathman