Многоколонный индекс и производительность

31

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

Сценарий:

  • PostgreSQL 8.4, таблица с около миллиона строк

  • Значения в столбце c1 могут иметь около 100 различных значений . Мы можем предположить, что значения распределены равномерно, поэтому у нас есть около 10000 строк для каждого возможного значения.

  • Столбец с2 может иметь 1000 различных значений . У нас есть 1000 строк для каждого возможного значения.

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

У меня такой вопрос:

Учитывая тот факт, что один из фильтров выбирает гораздо меньший набор данных, могу ли я улучшить производительность, если первый индекс является наиболее селективным (тот, который позволяет меньший набор)? Я никогда не рассматривал этот вопрос, пока не увидел графику из ссылочной статьи:

введите описание изображения здесь

Изображение взято из ссылочной статьи о многоколоночных индексах .

В запросах для фильтрации используются значения из двух столбцов. У меня нет запросов, использующих только один столбец для фильтрации. Все они являются WHERE c1=@ParameterA AND c2=@ParameterB. Есть также такие условия:WHERE c1 = "abc" AND c2 LIKE "ab%"

jap1968
источник

Ответы:

36

Ответ

Поскольку вы ссылаетесь на сайт use-the-index-luke.com, рассмотрите главу:

Используйте Индекс, Лука ›Пункт« Где »› Поиск диапазонов › Больше, Меньше и МЕЖДУ

У него есть пример, который идеально подходит к вашей ситуации (двухколонный индекс, один проверяется на равенство , другой на диапазон ), объясняет (с большим количеством этих прекрасных графиков индекса), почему совет @ ypercube является точным, и суммирует его:

Rule of thumb: index for equality first  then for ranges.

Также хорошо только для одного столбца?

Что делать для запросов на только по одному столбцу, похоже, понятно. Более подробная информация и критерии относительно этого по этим связанным вопросам:

Менее избирательный столбец в первую очередь?

Кроме того, что если у вас есть только условия равенства для обоих столбцов ?

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

Подумайте об этой демонстрации или воспроизведите ее самостоятельно. Я создаю простую таблицу из двух столбцов с 100k строк. Один с очень немногими , другой с множеством различных значений:

CREATE TEMP TABLE t AS
SELECT (random() * 10000)::int AS lots
     , (random() * 4)::int     AS few
FROM generate_series (1, 100000);

DELETE FROM t WHERE random() > 0.9;  -- create some dead tuples, more "real-life"

ANALYZE t;

SELECT count(distinct lots)   -- 9999
     , count(distinct few)    --    5
FROM   t;

Запрос:

SELECT *
FROM   t
WHERE  lots = 2345
AND    few = 2;

EXPLAIN ANALYZE Вывод (лучший из 10, чтобы исключить эффекты кэширования):

Seq Scan на t (стоимость = 0.00..5840.84 строки = 2 ширина = 8)
               (фактическое время = 5.646..15.535 строк = 2 цикла = 1)
  Фильтр: ((лоты = 2345) И (несколько = 2))
  Буферы: локальный хит = 443
Общее время выполнения: 15,557 мс

Добавить индекс, повторить тестирование:

CREATE INDEX t_lf_idx ON t(lots, few);
Сканирование индекса с использованием t_lf_idx на t (стоимость = 0.00..3.76 строк = 2 ширины = 8)
                                (фактическое время = 0.008..0.011 строк = 2 цикла = 1)
  Индекс Cond: ((лоты = 2345) И (несколько = 2))
  Буферы: локальный хит = 4
Общее время выполнения: 0,027 мс

Добавьте другой индекс, повторите тестирование:

DROP INDEX t_lf_idx;
CREATE INDEX t_fl_idx  ON t(few, lots);
Сканирование индекса с использованием t_fl_idx на t (стоимость = 0.00..3.74 строки = 2 ширина = 8)
                                (фактическое время = 0.007..0.011 строк = 2 цикла = 1)
  Индекс Cond: ((несколько = 2) И (много = 2345))
  Буферы: локальный хит = 4
Общее время выполнения: 0,027 мс
Эрвин Брандштеттер
источник
Это также относится к 3 (или более) столбцам в индексе?
Хайд
@hayd: Не уверен, что означает «это». Вы можете задать новый вопрос . Вы всегда можете обратиться к этому для контекста. (И оставьте комментарий здесь для обратной ссылки.)
Эрвин Брандштеттер
Под "этим" я подразумеваю "имеет ли значение порядок определения индекса, если в определении индекса более 2 столбцов"
Хайд
@hayd: Самый важный момент: индекс btree хорош для запросов с условиями равенства в ведущих выражениях индекса. Порядок среди тех в основном не имеет значения. Многие другие детали, которые не вписываются в комментарии ...
Эрвин Брандштеттер
Спасибо, я постараюсь написать связный вопрос и ссылку на него.
hayd
11

Если, как вы говорите, запросы, включающие эти 2 столбца, являются проверками равенства обоих столбцов, например:

WHERE c1=@ParameterA AND c2=@ParameterB

не заморачивайся с этим. Я сомневаюсь, что будет какая-то разница, и если она будет, она будет незначительной. Конечно, вы всегда можете проверить свои данные и настройки сервера. Различные версии СУБД могут вести себя немного по-разному в отношении оптимизации.

Порядок внутри индекса будет иметь значение для других типов запросов, имеющих проверки только для одного столбца, или условия неравенства, или условия для одного столбца, и группировки для другого, и т. Д.

Если бы я выбрал один из двух заказов, я бы предпочел поставить менее избирательный столбец первым. Рассмотрим таблицу со столбцами yearи month. Более вероятно, что вам нужно WHERE year = 2000условие или а WHERE year BETWEEN 2000 AND 2013или а WHERE (year, month) BETWEEN (1999, 6) AND (2000, 5).

Можно запросить запрос типа WHERE month = 7 GROUP BY year(Найти людей, родившихся в июле), но будет реже. Это зависит, конечно, от фактических данных, хранящихся в вашей таблице. Выберите один заказ на данный момент, скажите, (c1, c2)и вы всегда можете добавить другой индекс позже (c2, c1).


Обновление после комментария ОП:

Есть также такие условия: WHERE c1 = 'abc' AND c2 LIKE 'ab%'

Этот тип запроса, если точно условие диапазона для c2столбца и будет нуждаться в (c1, c2)индексе. Если у вас также есть запросы обратного типа:

WHERE c2 = 'abc' AND c1 LIKE 'ab%'

тогда было бы хорошо, если бы у вас был (c2, c1)индекс.

ypercubeᵀᴹ
источник