PostgreSql: разные планы запросов с одинаковыми столбцами - PullRequest
3 голосов
/ 01 июля 2010

У меня есть таблица с 2 внешними ключами, давайте назовем их fk1 и fk2. Оба имеют одинаковые типы и идентичные индексы. Но когда я «объясняю» простой запрос выбора, я получаю совершенно другие планы запросов. Для fk1:

explain select * from mytable where fk1 = 1;

Результат

Index Scan using fk1_idx on mytable  (cost=0.00..9.32 rows=2 width=4)
  Index Cond: (fk1 = 1)

Для ФК2

explain select * from mytable where fk2 = 1;

Результат:

Bitmap Heap Scan on mytable  (cost=5.88..659.18 rows=208 width=4)
  Recheck Cond: (fk2 = 1)
  ->  Bitmap Index Scan on fk2_idx  (cost=0.00..5.83 rows=208 width=0)
        Index Cond: (fk2 = 1)

Второй кажется более неэффективным. Это связано с тем, что он потенциально возвращает больше результатов и, следовательно, более сложный запрос окупается?

Ответы [ 2 ]

6 голосов
/ 01 июля 2010

Да, это сводится к тому, что называется «селективностью» предиката (предложение «где ...»).

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

По мере увеличения количества выбираемых строк растровое сканирование становится более подходящим: индекс используется для определения того, какие страницы в таблице являются «интересными», а затем эти страницы сканируются в порядке их размещения в файл данных таблицы. Это имеет то преимущество, что смежные страницы могут запрашиваться вместе, что, вероятно, будет гораздо более эффективно обслуживаться файловой системой / дисковой системой. (Конечно, это зависит от того, что файл табличных данных достаточно не фрагментирован). Поскольку набор реальных интересных кортежей на каждой странице не сохраняется, а только набор самих страниц, предикат должен быть переоценен для каждого кортежа на найденных страницах: отсюда и «reheck cond» в запросе. (Одним из преимуществ этой стратегии является то, что она позволяет объединять поиски в нескольких независимых индексах, просто добавляя (или ORing) вместе растровые изображения «интересных страниц» из нескольких поисков по индексам)

По мере того, как число строк, которые нужно выбрать, еще больше возрастает, преимущество сканирования индекса уменьшается, поскольку вероятный результат состоит в том, что большая часть таблицы будет помечена как "интересная". Таким образом, в конечном итоге становится целесообразным простое последовательное сканирование: все страницы проходят по порядку, а индекс игнорируется.

IIRC позволяет понять, что запрос менее 15% таблицы, скорее всего, является сканированием индекса, 15-50% сканированием растрового изображения, 50% + сканированием последовательности. Очень грубо На это сильно влияют относительные настройки random_page_cost и seq_page_cost, среди прочих (например ,ffective_cache_size).

Postgresql собирает статистику об общих значениях и их частотах, а также гистограммы других значений для каждого столбца в базе данных - это используется для оценки селективности и заполняет оценку «строк», которую вы видели в выводе EXPLAIN. Документация содержит описание того, как это делается: http://www.postgresql.org/docs/current/static/planner-stats-details.html

2 голосов
/ 01 июля 2010

Да, план запроса будет основан на статистических данных о содержании в таблицах. Не забудьте запустить «анализ вакуума»; время от времени поддерживать статистические данные до данных.

...