Я пытаюсь воспользоваться многостолбцовым индексом btree в PostgreSQL для выполнения раздражающего соединения двух таблиц.
Table "revision_main"
Column | Type | Modifiers
----------------+------------------------+-----------
revision_id | integer |
page_id | integer |
Indexes:
"revision_main_pkey" UNIQUE, btree (revision_id)
"revision_main_cluster_idx" btree (page_id, "timestamp") CLUSTER
Эта таблица содержит изменения (~ 300 миллионов строк) страниц в вики. В моей таблице больше столбцов, но я отбросил их для этого примера, потому что они не должны иметь значения.
Table "revert"
Column | Type | Modifiers
--------------------+---------+-----------
page_id | integer |
revision_id | integer |
reverted_to | integer |
Indexes:
"revert_page_between_idx" btree (page_id, reverted_to, revision_id) CLUSTER
Эта таблица содержит возвращаемые ревизии (~ 22 миллиона строк). Если ревизия была отменена, этот revision_id будет иметь строку в таблице revision_main, а его revision_id будет находиться между reverted_to и revision_id, а также будет использовать один и тот же page_id. (См. http://en.wikipedia.org/wiki/Wikipedia:Revert, если вам интересно.)
Соединение этих двух таблиц для получения отредактированных версий кажется простым. Вот что я придумала:
explain SELECT
r.revision_id,
rvt.revision_id
FROM revision_main r
INNER JOIN revert rvt
ON r.page_id = rvt.page_id
AND r.revision_id > rvt.reverted_to
AND r.revision_id < rvt.revision_id;
QUERY PLAN
----------------------------------------------------------------------------------------------------
Merge Join (cost=4202878.87..15927491478.57 rows=88418194298 width=8)
Merge Cond: (r.page_id = rvt.page_id)
Join Filter: ((r.revision_id > rvt.reverted_to) AND (r.revision_id < rvt.revision_id))
-> Index Scan using revision_main_page_id_idx on revision_main r (cost=0.00..9740790.61 rows=223163392 width=8)
-> Materialize (cost=4201592.06..4536465.21 rows=26789852 width=12)
-> Sort (cost=4201592.06..4268566.69 rows=26789852 width=12)
Sort Key: rvt.page_id
-> Seq Scan on revert rvt (cost=0.00..438534.52 rows=26789852 width=12)
Несмотря на то, что кластеризованный индекс при возврате должен быть индексом Btree (и, следовательно, поддерживать операторы сравнения, такие как «<» и «>»), оптимизатор запросов не использует индекс для объединения, а «объяснение» прогнозирует общую стоимость более 15 миллиардов (может быть сделано в следующем году).
Нельзя ли использовать операторы сравнения с многостолбцовыми (btree) индексами? Я просто делаю это неправильно?