2014-09-06 105 views
-1
SELECT "Series".* 
    ,"SeriesTranslations"."id" AS "SeriesTranslations.id" 
    ,"SeriesTranslations"."title" AS "SeriesTranslations.title" 
    ,"SeriesTranslations"."subtitle" AS "SeriesTranslations.subtitle" 
    ,"SeriesTranslations"."slug" AS "SeriesTranslations.slug" 
    ,"SeriesTranslations"."language" AS "SeriesTranslations.language" 
    ,"SeriesTranslations"."seoTitle" AS "SeriesTranslations.seoTitle" 
    ,"SeriesTranslations"."seoDescription" AS "SeriesTranslations.seoDescription" 
    ,"Posts"."id" AS "Posts.id" 
    ,"Posts"."type" AS "Posts.type" 
    ,"Posts"."contentDuration" AS "Posts.contentDuration" 
    ,"Posts"."publishDate" AS "Posts.publishDate" 
    ,"Posts"."publishedAt" AS "Posts.publishedAt" 
    ,"Posts"."thumbnailUrl" AS "Posts.thumbnailUrl" 
    ,"Posts"."imageUrl" AS "Posts.imageUrl" 
    ,"Posts"."media" AS "Posts.media" 
    ,"Posts.PostTranslations"."id" AS "Posts.PostTranslations.id" 
    ,"Posts.PostTranslations"."slug" AS "Posts.PostTranslations.slug" 
    ,"Posts.PostTranslations"."title" AS "Posts.PostTranslations.title" 
    ,"Posts.PostTranslations"."subtitle" AS "Posts.PostTranslations.subtitle" 
    ,"Posts.PostTranslations"."language" AS "Posts.PostTranslations.language" 
FROM (
    SELECT "Series"."id" 
    ,"Series"."thumbnailUrl" 
    ,"Series"."imageUrl" 
    ,"Series"."coverUrl" 
    FROM "Series" AS "Series" 
    WHERE EXISTS (
     SELECT * 
     FROM "SeriesTranslations" AS t 
     WHERE t.LANGUAGE IN ('en-us') 
     AND t.slug = 'in-residence-architecture-design-video-series' 
     AND t."SeriesId" = "Series"."id" LIMIT 1 
    ) LIMIT 1 
) AS "Series" 
INNER JOIN "SeriesTranslations" AS "SeriesTranslations" ON "Series"."id" = "SeriesTranslations"."SeriesId" 
    AND "SeriesTranslations"."language" IN ('en-us') 
LEFT JOIN "Posts" AS "Posts" ON "Series"."id" = "Posts"."SeriesId" 
    AND EXISTS (
    SELECT * 
    FROM "PostTranslations" AS pt 
    WHERE pt.LANGUAGE IN ('en-us') 
     AND pt."PostId" = "Posts"."id" LIMIT 1 
    ) 
LEFT JOIN "PostTranslations" AS "Posts.PostTranslations" ON "Posts"."id" = "Posts.PostTranslations"."PostId" 
    AND "Posts.PostTranslations"."language" IN ('en-us') 
ORDER BY "Posts"."publishDate" DESC; 

它從4個表格「系列」,「系列翻譯」,「帖子」和「帖子翻譯」加載數據。我根據「SeriesTranslations」slug檢索單個「系列」,並檢索屬於本系列的所有「Posts」及其翻譯。爲什麼我的查詢很慢?

當系列返回14個帖子(共14行從查詢返回)時,此查詢花費約1.5秒。在DB中只有幾個系列(不超過5個),每個系列有兩個翻譯。然而也有在DB很多職位 - 2000年左右,每一個有2名翻譯,以便圍繞4K PostTranslations ...


這裏是EXPLAIN結果

enter image description here

我有「蛞蝓唯一索引」, 「」,在 「SeriesTranslations」 和 「PostTranslations」 還我已經forign鍵上的 「文章」。 「SeriesId」, 「SeriesTranslations」。 「SeriesId」 和 「PostTranslations」。 「帖子ID」


語言

在這裏解釋http://explain.depesz.com/s/fhm


我簡化了查詢的建議:(取出一個子查詢,搬到條件內加入) - 但是查詢仍然緩慢...

SELECT "Series"."id" 
    ,"Series"."thumbnailUrl" 
    ,"Series"."imageUrl" 
    ,"Series"."coverUrl" 
    ,"SeriesTranslations"."id" AS "SeriesTranslations.id" 
    ,"SeriesTranslations"."title" AS "SeriesTranslations.title" 
    ,"SeriesTranslations"."subtitle" AS "SeriesTranslations.subtitle" 
    ,"SeriesTranslations"."slug" AS "SeriesTranslations.slug" 
    ,"SeriesTranslations"."language" AS "SeriesTranslations.language" 
    ,"SeriesTranslations"."seoTitle" AS "SeriesTranslations.seoTitle" 
    ,"SeriesTranslations"."seoDescription" AS "SeriesTranslations.seoDescription" 
    ,"Posts"."id" AS "Posts.id" 
    ,"Posts"."type" AS "Posts.type" 
    ,"Posts"."contentDuration" AS "Posts.contentDuration" 
    ,"Posts"."publishDate" AS "Posts.publishDate" 
    ,"Posts"."publishedAt" AS "Posts.publishedAt" 
    ,"Posts"."thumbnailUrl" AS "Posts.thumbnailUrl" 
    ,"Posts"."imageUrl" AS "Posts.imageUrl" 
    ,"Posts"."media" AS "Posts.media" 
    ,"Posts.PostTranslations"."id" AS "Posts.PostTranslations.id" 
    ,"Posts.PostTranslations"."slug" AS "Posts.PostTranslations.slug" 
    ,"Posts.PostTranslations"."title" AS "Posts.PostTranslations.title" 
    ,"Posts.PostTranslations"."subtitle" AS "Posts.PostTranslations.subtitle" 
    ,"Posts.PostTranslations"."language" AS "Posts.PostTranslations.language" 
FROM "Series" AS "Series" 
INNER JOIN "SeriesTranslations" AS "SeriesTranslations" ON "Series"."id" = "SeriesTranslations"."SeriesId" 
    AND "SeriesTranslations"."language" IN ('en-us') 
    AND "SeriesTranslations"."slug" = 'sdf' 
LEFT JOIN "Posts" AS "Posts" ON "Series"."id" = "Posts"."SeriesId" 
    AND EXISTS (
     SELECT * 
     FROM "PostTranslations" AS pt 
     WHERE pt.LANGUAGE IN ('en-us') 
      AND pt."PostId" = "Posts"."id" LIMIT 1 
     ) 
LEFT JOIN "PostTranslations" AS "Posts.PostTranslations" ON "Posts"."id" = "Posts.PostTranslations"."PostId" 
    AND "Posts.PostTranslations"."language" IN ('en-us') 
WHERE (1 = 1) 
ORDER BY "Posts"."publishDate" DESC 
    ,"Posts"."id" DESC; 

這裏是新的查詢計劃:

                     QUERY PLAN                      
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 
Sort (cost=1014671.76..1014671.76 rows=1 width=695) (actual time=2140.906..2140.908 rows=14 loops=1) 
    Sort Key: "Posts"."publishDate", "Posts".id 
    Sort Method: quicksort Memory: 45kB 
    -> Nested Loop Left Join (cost=0.03..1014671.76 rows=1 width=695) (actual time=85.862..2140.745 rows=14 loops=1) 
     Join Filter: ("Posts".id = "Posts.PostTranslations"."PostId") 
     Rows Removed by Join Filter: 28266 
     -> Nested Loop (cost=0.03..1014165.24 rows=1 width=564) (actual time=85.307..2042.304 rows=14 loops=1) 
       Join Filter: ("Series".id = "SeriesTranslations"."SeriesId") 
       Rows Removed by Join Filter: 35 
       -> Index Scan using "SeriesTranslations-slug-language-unique" on "SeriesTranslations" (cost=0.03..4.03 rows=1 width=200) (actual time=0.044..0.046 rows=1 loops=1) 
        Index Cond: ((slug = 'in-residence-architecture-design-video-series'::text) AND (language = 'en-us'::text)) 
       -> Nested Loop Left Join (cost=0.00..1014159.63 rows=450 width=368) (actual time=85.243..2042.207 rows=49 loops=1) 
        Join Filter: ("Series".id = "Posts"."SeriesId") 
        Rows Removed by Join Filter: 18131 
        -> Seq Scan on "Series" (cost=0.00..11.35 rows=450 width=100) (actual time=0.006..0.046 rows=9 loops=1) 
        -> Materialize (cost=0.00..1.79 rows=1010 width=272) (actual time=4.422..226.499 rows=2020 loops=9) 
          -> Seq Scan on "Posts" (cost=0.00..1.78 rows=1010 width=272) (actual time=39.785..2020.448 rows=2020 loops=1) 
           Filter: (SubPlan 1) 
           SubPlan 1 
            -> Limit (cost=0.00..500.94 rows=1 width=1267) (actual time=0.995..0.995 rows=1 loops=2020) 
             -> Seq Scan on "PostTranslations" pt (cost=0.00..500.94 rows=1 width=1267) (actual time=0.992..0.992 rows=1 loops=2020) 
               Filter: ((language = 'en-us'::text) AND ("PostId" = "Posts".id)) 
               Rows Removed by Filter: 1591 
     -> Seq Scan on "PostTranslations" "Posts.PostTranslations" (cost=0.00..499.44 rows=2020 width=135) (actual time=0.003..3.188 rows=2020 loops=14) 
       Filter: (language = 'en-us'::text) 
       Rows Removed by Filter: 964 
Total runtime: 2141.432 ms 
(27 rows) 
+2

這不是一個簡單的查詢,你有解釋運行它嗎?你有索引嗎? – 2014-09-06 13:42:28

+0

我編輯了我的問題,解釋了我的結果和索引。 – user606521 2014-09-06 13:51:02

+0

「EXISTS(...)」子查詢中的「LIMIT 1」完全沒用。 – wildplasser 2014-09-06 13:53:48

回答

1

在FKS的指數可能有助於連接:

CREATE INDEX ON PostTranslations (PostId); -- For FK 
VACUUM ANALYZE PostTranslations ; -- refresh statistics 

CREATE INDEX ON SeriesTranslations (SeriesId); -- FK 
VACUUM ANALYZE SeriesTranslations ; 

CREATE INDEX ON Posts (SeriesId) ; -- FK 
VACUUM ANALYZE Posts ; 

And REMOVELIMIT 1 from EXISTS(...)子查詢。他們只能做傷害。

+0

我認爲索引是自動創建的外鍵??我總是在存在中使用限制1(有時是I我實際上是在查詢更多的行) - 如果存在極限,它真的很重要嗎? – user606521 2014-09-06 15:46:36

+1

否,FK的*目標*需要*至少* UNIQUE約束。 (* source *)FK本身不需要*具有索引。 (但它有幫助)'EXITTS(...)'子查詢中的'LIMIT 1'完全無能爲力(mysql-ism?):它存在或者它不存在。 – wildplasser 2014-09-06 15:48:52

+0

它加速查詢50%,但我認爲它仍然太慢。也許我應該在「PostTranslations」(語言,PostId)上添加索引? – user606521 2014-09-06 23:11:46