Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.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
PostgreSQL如何处理1+n查询?_Sql_Postgresql - Fatal编程技术网

PostgreSQL如何处理1+n查询?

PostgreSQL如何处理1+n查询?,sql,postgresql,Sql,Postgresql,我正在对Sakila数据库进行测试,请参阅。该数据库包含三种关系: 电影:电影id,片名 演员:演员id,名字 电影演员:电影id,演员id 我想列出所有的电影,对于每部电影,我想列出在这部电影中扮演的所有演员。我以以下问题结束: select film_id, title, array ( select first_name from actor inner join film_acto

我正在对Sakila数据库进行测试,请参阅。该数据库包含三种关系:

电影:电影id,片名 演员:演员id,名字 电影演员:电影id,演员id 我想列出所有的电影,对于每部电影,我想列出在这部电影中扮演的所有演员。我以以下问题结束:

select   film_id, title, array
         (
           select     first_name
           from       actor
           inner join film_actor
           on         actor.actor_id = film_actor.actor_id
           where      film_actor.film_id = film.film_id
         ) as actors
from     film
order by title;
从概念上讲,这是一个1+n查询:

我一直明白,应该不惜一切代价避免1+n查询,因为这不能很好地扩展

这让我想知道:PostgreSQL是如何在内部实现的?假设我们有1000部电影,它是否在内部执行1000个select actor.first_name from actor internal join。。。询问?或者PostgreSQL在这方面更聪明,它是否类似于以下内容

1. one query:  get films
2. one query:  get actors related to these films while keeping reference to film_id
3. internally: for each film f
                 f.actors = array(subset of (2) according to film_id)

这会执行1+1查询。

这可能更适合用于注释,但它太长了

虽然我遵循您的查询逻辑,但我更喜欢将其表达为:

select f.film_id, f.title,
       (select array_agg(a.first_name)
        from actor a inner join
             film_actor fa
             on a.actor_id = fa.actor_id
        where fa.film_id = f.film_id
       ) as actors
from film f
order by f.title;

显式数组_agg澄清了逻辑。您正在聚合子查询,将结果合并为一个数组,然后将其作为列包含在外部查询中。

您正在嵌套循环中思考。除非您使用的是MySQL,否则在使用关系数据库时应该克服这一点

您所描述的1+n是一个嵌套循环:您扫描一个表,对于找到的每一行,您扫描另一个表

按照编写SQL查询的方式,PostgreSQL别无选择,只能执行嵌套循环

只要示例中的表外贴膜只有几行,这就很好。一旦外部桌子变大,性能就会迅速恶化

除了嵌套循环,PostgreSQL还有两种其他连接策略:

哈希连接:扫描内部关系并创建哈希结构,其中哈希键是连接键。然后扫描外部关系,并为找到的每一行探测哈希

可以将其视为一种散列连接,但在内部,您有一个高效的内存中数据结构

合并联接:两个表在联接键上排序,并通过同时扫描结果进行合并

建议您在编写查询时不要使用“相关子查询”,以便PostgreSQL可以选择最佳连接策略:

SELECT film_id, f.title, array_agg(a.first_name)
FROM film f
   LEFT JOIN film_actor fa USING (film_id)
   LEFT JOIN actor a USING (actor_id)
GROUP BY f.title
ORDER BY f.title;

使用左外连接,这样即使电影中没有演员,也能得到结果。

还有:太好了!我不知道有这样的分析工具。我渴望了解更多。现在我该如何处理这个问题?我可以在几天内开始学习解释和回答我的问题?快速提示与您的问题无关,但它有助于简化一些查询-当仅使用名称相同的列连接两个表时,您可以使用。选择*从演员内部加入电影(演员使用演员)你是对的,使用数组(agg)可以更清楚地了解我们在做什么。谢谢你的建议。这很有趣,谢谢!我必须在您的查询中按f.film_id添加一个组,对吗?分组是否会带来我们在相关子查询中没有的额外性能损失?因此,一般来说,最好用左连接替换相关子查询?我在问自己,为什么查询规划器不能自己将相关子查询转换为左连接:我忘记了GROUB by-fixed。当然,这会导致一些问题,但嵌套lop也是如此。将它们与解释分析进行比较,然后您将看到什么更快。是的,编写左连接比编写相关子查询更好。也许优化器足够聪明,可以将子查询展平,但是没有必要让PostgreSQL变得更加困难。我同意这一点,阅读它确实更好,我们不应该让它变得比需要的更困难。
SELECT film_id, f.title, array_agg(a.first_name)
FROM film f
   LEFT JOIN film_actor fa USING (film_id)
   LEFT JOIN actor a USING (actor_id)
GROUP BY f.title
ORDER BY f.title;