Postgresql
為什麼儘管對列進行了索引排序,但查詢計劃仍然對錶進行排序?
我正在使用 Postgres 9.1 我有兩個要加入的表:
wikidb=> \d page Table "public.page" Column | Type | Modifiers -----------------------+---------------+------------------------------ page_id | bigint | not null page_namespace | integer | not null default 0 page_title | text | not null default ''::text [...] Indexes: [...] "page_page_namespace_page_title_idx" UNIQUE, btree (page_namespace, page_title) wikidb=> \d pagelinks Table "public.pagelinks" Column | Type | Modifiers -------------------+---------+---------------------------- pl_from | bigint | not null default 0::bigint pl_namespace | integer | not null default 0 pl_title | text | not null default ''::text [...] Indexes: [...] "pagelinks_pl_namespace_pl_title_pl_from_idx" btree (pl_namespace, pl_title, pl_from)
請注意兩者在 (namespace, title) 列上的索引。我有興趣找出 pagelinks 表中有多少 (pl_namespace,pl_title) 對沒有在頁表中顯示為 (page_namespace, page_title)。
如果我使用聯接,那麼我會得到以下計劃:
wikidb=> explain SELECT COUNT(*) FROM pagelinks LEFT OUTER JOIN page ON page.page_namespace = pagelinks.pl_namespace AND page.page_title = pagelinks.pl_title WHERE page.page_namespace IS NULL AND page.page_title IS NULL; QUERY PLAN ----------------------------------------------------------------------------------------------------------------- Aggregate (cost=1310748.56..1310748.57 rows=1 width=0) -> Merge Anti Join (cost=1189384.02..1310748.56 rows=1 width=0) Merge Cond: ((pagelinks.pl_title = page.page_title) AND (pagelinks.pl_namespace = page.page_namespace)) -> Sort (cost=1144343.89..1164498.31 rows=8061768 width=19) Sort Key: pagelinks.pl_title, pagelinks.pl_namespace -> Seq Scan on pagelinks (cost=0.00..219551.68 rows=8061768 width=19) -> Sort (cost=45038.32..45975.52 rows=374880 width=20) Sort Key: page.page_title, page.page_namespace -> Seq Scan on page (cost=0.00..10331.80 rows=374880 width=20) (9 rows)
如您所見,它對兩個表中的每一個進行排序並合併它們。如果索引已經按排序順序包含兩列,我不明白為什麼會這樣做。
有什麼解釋嗎?
如果索引已經按排序順序包含兩列,我不明白為什麼會這樣做。
我正在使用 Postgres 9.1。
最重要的是,僅索引掃描是 Postgres 9.2添加的主要性能特性。Postgres Wiki 中的詳細資訊。
考慮升級到目前版本,Postgres 9.1 無論如何都會變舊。
在舊版本中,Postgres 必須以任何一種方式訪問表,因此索引必須提供更多的性能改進才能克服增加的成本。並且
UNIQUE
索引告訴我們,每個 最多有一行(page_namespace, page_title)
,所以你的索引不會有太大幫助——如果有的話,當你計算整個表時。一個小的改進:
SELECT COUNT(*) AS ct FROM pagelinks l LEFT JOIN page p ON p.page_namespace = l.pl_namespace AND p.page_title = l.pl_title WHERE p.page_namespace IS NULL; AND p.page_title IS NULL;
只測試一列已經證明了所有需要證明的東西。
否則,您的查詢幾乎是最佳的。也許
NOT EXISTS
可以競爭:SELECT count(*) AS ct FROM pagelinks l WHERE NOT EXISTS ( SELECT 1 FROM page WHERE page_namespace = l.pl_namespace AND page_title = l.pl_title );
連接或
NOT IN
行表達式(pl_namespace,pl_title)
通常較慢。基本技術: