Что произойдёт, если таблица разбита на партиции по одному столбцу, а запрос выполняется по условию на другом столбце?

Ответ

Это приведёт к полному сканированию таблицы (Full Table Scan), так как механизм партиционирования не сможет выполнить "отсечение партиций" (partition pruning). Запрос будет вынужден проверить каждую партицию, что сведёт на нет основное преимущество партиционирования — уменьшение объёма данных для чтения.

Конкретный пример в PostgreSQL:

-- Создаём таблицу, партиционированную по дате
CREATE TABLE sensor_data (
    sensor_id INT,
    recorded_at DATE,
    value DECIMAL
) PARTITION BY RANGE (recorded_at);

CREATE TABLE sensor_data_2023 PARTITION OF sensor_data
    FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');
CREATE TABLE sensor_data_2024 PARTITION OF sensor_data
    FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');

-- Запрос по партиционному ключу — БЫСТРО (чтение только из одной партиции)
SELECT * FROM sensor_data WHERE recorded_at = '2024-06-15'; -- Сканируется только sensor_data_2024

-- Запрос по НЕпартиционному ключу — МЕДЛЕННО (чтение из ВСЕХ партиций)
SELECT * FROM sensor_data WHERE sensor_id = 123; -- Сканируется sensor_data_2023 И sensor_data_2024

Как оптимизировать такой сценарий:

  1. Добавить индекс на столбец sensor_id. Это ускорит поиск внутри каждой партиции, но не избавит от необходимости обхода всех партиций.
  2. Изменить стратегию партиционирования, если это возможно по логике данных. Например, сделать составной ключ PARTITION BY RANGE (recorded_at, sensor_id) или хэш-партиционирование по sensor_id.
  3. Спроектировать запросы так, чтобы они всегда включали условие по партиционному ключу. Например, сначала найти диапазоны дат для нужного sensor_id, а затем делать запрос с фильтром и по recorded_at.

Вывод: Партиционирование — это не замена индексам, а инструмент для физического разделения данных. Его эффективность напрямую зависит от того, как вы фильтруете данные в запросах.

Ответ 18+ 🔞

А, ну это же классика, ёпта! Смотри, тут история про то, как партиционирование может накрыться медным тазом, если им неправильно пользоваться.

Вот представь: ты нагородил кучу партиций по дате, чтобы быстро искать данные за конкретный день. А потом приходит запрос, который ищет не по дате, а по какому-нибудь sensor_id. И что происходит? А происходит пиздец, Карл! Механизму партиционирования нужно выполнить так называемое "отсечение партиций" (partition pruning), чтобы не читать всё подряд. Но если в запросе нет условия по той колонке, по которой ты партиционировал, то отсечь нихуя не получится. Движку придётся лезть в каждую, блядь, партицию и там уже искать. Весь смысл партиционирования — уменьшить объём данных для чтения — летит коту под хвост. Получается полное сканирование таблицы (Full Table Scan), только ещё и по всем партициям разом. Удивление пиздец, да?

Вот смотри на примере PostgreSQL, тут всё понятно становится:

-- Делаем умную таблицу, разбитую по датам
CREATE TABLE sensor_data (
    sensor_id INT,
    recorded_at DATE,
    value DECIMAL
) PARTITION BY RANGE (recorded_at);

-- Отдельная партиция за 2023 год
CREATE TABLE sensor_data_2023 PARTITION OF sensor_data
    FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');
-- И за 2024
CREATE TABLE sensor_data_2024 PARTITION OF sensor_data
    FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');

-- Запрос по партиционному ключу — ЛЕТАЕТ! Читает только одну партицию.
SELECT * FROM sensor_data WHERE recorded_at = '2024-06-15'; -- Заглянет только в sensor_data_2024

-- А вот запрос по НЕпартиционному ключу — ПРОСРАЛСЯ. Полезет во все партиции подряд.
SELECT * FROM sensor_data WHERE sensor_id = 123; -- Будет рыться и в 2023, и в 2024, как свинья в огороде.

Ну и что с этим делать, спросишь ты? Варианты есть, но не все они панацея.

  1. Индекс на sensor_id налепить. Это поможет быстрее искать внутри каждой отдельной партиции, но от обязательного обхода всех партиций тебя не спасёт. Так что это как подтереться бумажкой, когда у тебя понос — легче, но проблему не решает.
  2. Пересмотреть всю стратегию партиционирования. Может, тебе на самом деле нужно партиционировать не по дате, а по sensor_id, или сделать составной ключ? Но это уже архитектурные танцы с бубном, не всегда возможно.
  3. Заставить разработчиков не выёбываться и писать запросы с условием по партиционному ключу. То есть, сначала как-то выяснить, в какие даты этот sensor_id = 123 вообще что-то записывал, а потом уже делать запрос с фильтром и по recorded_at. Но это, блядь, лишняя работа для мозга.

Так что вывод простой, как три копейки: партиционирование — это не волшебная таблетка и уж точно не замена индексам. Это просто способ раскидать данные по разным физическим коробкам. А будет от этого толк или один вред — зависит целиком от того, как ты эти данные потом ищешь. Если ищешь не по тому ключу, по которому раскидал, то эффективность — ноль ебать.