Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 在复杂查询中计算行的方式有什么问题?_Sql_Database_Postgresql_Count_Postgresql Performance - Fatal编程技术网

Sql 在复杂查询中计算行的方式有什么问题?

Sql 在复杂查询中计算行的方式有什么问题?,sql,database,postgresql,count,postgresql-performance,Sql,Database,Postgresql,Count,Postgresql Performance,我有一个数据库,有几个表,每个表都有几百万行,表都有索引。我需要计算表中的行数,但只计算外键字段指向另一个表的子集的行数。 以下是查询: WITH filtered_title AS (SELECT top.id FROM title top WHERE ( top.production_year >= 1982 AND top.production_year <= 1984

我有一个数据库,有几个表,每个表都有几百万行,表都有索引。我需要计算表中的行数,但只计算外键字段指向另一个表的子集的行数。 以下是查询:

WITH filtered_title 
     AS (SELECT top.id 
         FROM   title top 
         WHERE  ( top.production_year >= 1982 
                  AND top.production_year <= 1984 
                  AND top.kind_id IN( 1, 2 ) 
                   OR EXISTS(SELECT 1 
                             FROM   title sub 
                             WHERE  sub.episode_of_id = top.id 
                                    AND sub.production_year >= 1982 
                                    AND sub.production_year <= 1984 
                                    AND sub.kind_id IN( 1, 2 )) )) 
SELECT Count(*) 
FROM   cast_info 
WHERE  EXISTS(SELECT 1 
              FROM   filtered_title 
              WHERE  cast_info.movie_id = filtered_title.id) 
       AND cast_info.role_id IN( 3, 8 ) 
现在回答我的问题。我做错了什么?我该如何修复它

我尝试了同一查询的几个变体:独占联接、联接/存在。一方面,这项工作似乎需要最少的时间来完成10倍的速度,但平均仍需要60秒。另一方面,与我的第一个查询在第二次运行时需要4-6秒不同,它总是需要60秒

WITH filtered_title 
     AS (SELECT top.id 
         FROM   title top 
         WHERE  top.production_year >= 1982 
                AND top.production_year <= 1984 
                AND top.kind_id IN( 1, 2 ) 
                 OR EXISTS(SELECT 1 
                           FROM   title sub 
                           WHERE  sub.episode_of_id = top.id 
                                  AND sub.production_year >= 1982 
                                  AND sub.production_year <= 1984 
                                  AND sub.kind_id IN( 1, 2 ))) 
SELECT Count(*) 
FROM   cast_info 
       join filtered_title 
         ON cast_info.movie_id = filtered_title.id 
WHERE  cast_info.role_id IN( 3, 8 ) 
免责声明:有太多的因素在起作用,给一个决定性的答案。有几个表的信息,每个表都有几百万行,表有索引,但不能将其剪切。它取决于基数、表定义、数据类型、使用模式以及可能最重要的索引。当然,还有数据库服务器的正确基本配置。所有这些都超出了一个问题的范围。从标记中的链接开始。或者请一位专业人士

我将在您的查询计划中为我介绍最突出的细节:

标题的顺序扫描? ->标题子标题上的顺序扫描成本=0.00..90471.23行=11657宽度=4实际时间=0.071..730.311行=16250循环=1 过滤器:生产年份>=1982和生产年份免责声明:有太多因素在起作用,无法给出结论性答案。有几个表的信息,每个表都有几百万行,表有索引,但不能将其剪切。它取决于基数、表定义、数据类型、使用模式以及可能最重要的索引。当然,还有数据库服务器的正确基本配置。所有这些都超出了一个问题的范围。从标记中的链接开始。或者请一位专业人士

我将在您的查询计划中为我介绍最突出的细节:

标题的顺序扫描? ->标题子标题上的顺序扫描成本=0.00..90471.23行=11657宽度=4实际时间=0.071..730.311行=16250循环=1
筛选:production\u year>=1982和production\u year编辑您的问题,并在慢速查询上粘贴运行explain Analysis的输出。您的查询中有太多相关子计划。重写它以便使用普通联接(带有group by和having子句)获得结果,它的性能应该会更好。尝试使用联接重写它,它的工作速度确实快了6倍,但对于查询来说仍然是90秒,这仍然是。。。令人失望:编辑您的问题,并在慢速查询上粘贴运行解释分析的输出。您的查询中有太多相关子计划。重写它以便使用普通联接(带有group by和having子句)获得结果,它的性能应该会更好。尝试使用联接重写它,它的工作速度确实快了6倍,但对于查询来说仍然是90秒,这仍然是。。。令人失望:谢谢你的回答。我只有对数据库的只读访问权限,因此我不能更改索引或使用临时表。@Sanko:您只需要创建临时表。另外,在我花时间尝试帮助之前,你应该先提到这一点和其他基本信息。不管怎样,我建议的查询仍然会有帮助——程度要小一些。对不起。是的,你的回答很有帮助。谢谢。@Sanko:我想知道建议的替代方案在比较中的表现如何。如果你不介意的话,请在这里留言。我一分钟前测试过。您的查询很好,大约20秒,而EXISTS的查询速度大约慢5%。这些是我可以接受的结果。谢谢你的回答。我只有对数据库的只读访问权限,因此我不能更改索引或使用临时表。@Sanko:您只需要创建临时表。另外,在我花时间尝试帮助之前,你应该先提到这一点和其他基本信息。不管怎样,我建议的查询仍然会有帮助——程度要小一些。对不起。是的,你的回答很有帮助。谢谢。@Sanko:我想知道建议的替代方案在比较中的表现如何。如果你不介意的话,请在这里留言。我一分钟前测试过。您的查询很好,大约20秒,而EXISTS的查询速度大约慢5%。这些是我可以接受的结果。
WITH filtered_title 
     AS (SELECT top.id 
         FROM   title top 
         WHERE  top.production_year >= 1982 
                AND top.production_year <= 1984 
                AND top.kind_id IN( 1, 2 ) 
                 OR EXISTS(SELECT 1 
                           FROM   title sub 
                           WHERE  sub.episode_of_id = top.id 
                                  AND sub.production_year >= 1982 
                                  AND sub.production_year <= 1984 
                                  AND sub.kind_id IN( 1, 2 ))) 
SELECT Count(*) 
FROM   cast_info 
       join filtered_title 
         ON cast_info.movie_id = filtered_title.id 
WHERE  cast_info.role_id IN( 3, 8 ) 
CREATE INDEX title_foo_idx ON title (kind_id, production_year, id, episode_of_id)
WITH t_base AS (
   SELECT id, episode_of_id
   FROM   title
   WHERE  kind_id BETWEEN 1 AND 2
   AND    production_year BETWEEN 1982 AND 1984 
   )
, t_all AS (
   SELECT id FROM t_base

   UNION  -- not UNION ALL (!)
   SELECT id
   FROM  (SELECT DISTINCT episode_of_id AS id FROM t_base) x
   JOIN   title t USING (id)
   )
SELECT count(*) AS ct
FROM   cast_info c
JOIN   t_all t ON t.id = c.movie_id 
WHERE  c.role_id IN (3, 8);
   SELECT id
   FROM   title t 
   WHERE  EXISTS (SELECT 1 FROM t_base WHERE t_base.episode_of_id = t.id)
CREATE TEMP TABLE t_tmp AS
WITH t_base AS (
   SELECT id, episode_of_id
   FROM   title
   WHERE  kind_id BETWEEN 1 AND 2
   AND    production_year BETWEEN 1982 AND 1984 
   )
SELECT id FROM t_base
UNION
SELECT id FROM title t 
WHERE  EXISTS (SELECT 1 FROM t_base WHERE t_base.episode_of_id = t.id);

ANALYZE t_tmp;                       -- !
CREATE UNIQUE INDEX ON t_tmp (id);   -- ! (unique is optional)

SELECT count(*) AS ct
FROM   cast_info c
JOIN   t_tmp t ON t.id = c.movie_id 
WHERE  c.role_id IN (3, 8);

-- More queries using t_tmp