2014-09-06 178 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