Postgresql

為什麼儘管對列進行了索引排序,但查詢計劃仍然對錶進行排序?

  • September 18, 2015

我正在使用 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)通常較慢。

基本技術:

引用自:https://dba.stackexchange.com/questions/115402