Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.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_Postgresql - Fatal编程技术网

Sql 如何使用最有效的窗口功能在连接的值上构建聚合?

Sql 如何使用最有效的窗口功能在连接的值上构建聚合?,sql,postgresql,Sql,Postgresql,我在使用窗口函数在连接的值上构建聚合时遇到问题。看起来是这样的: 我得到了以下表格: CREATE TABLE movies ( id SERIAL, name VARCHAR, year INT, genre VARCHAR, country VARCHAR ); CREATE TABLE tags ( id SERIAL, name VARCHAR ); CREATE TABLE movies_tags (

我在使用窗口函数在连接的值上构建聚合时遇到问题。看起来是这样的:

我得到了以下表格:

  CREATE TABLE movies (
    id SERIAL,
    name VARCHAR,
    year INT,
    genre VARCHAR,
    country VARCHAR
  );

  CREATE TABLE tags (
    id SERIAL,
    name VARCHAR
  );

  CREATE TABLE movies_tags (
    id SERIAL,
    movie_id INT,
    tag_id INT
  );
现在我想做以下陈述:

  SELECT m.*, array_agg(t.name) AS tags
  FROM movies m
  LEFT JOIN movies_tags mt ON mt.movie_id = m.id
  LEFT JOIN tags t ON t.id = mt.tag_id
  ORDER BY m.name
  LIMIT 10
由于select中的聚合,所有电影在从大加入中选择前10名之前都会加入所有标签。我的目标是,出于性能方面的考虑,只对前10部电影进行汇总。所以我做的是:

  WITH top_movies AS (
    SELECT m.*
    FROM movies m
    ORDER BY m.name
    LIMIT 10
  )
  SELECT tm.*, array_agg(t.name) AS tags
  FROM top_movies tm
  LEFT JOIN movies_tags mt ON mt.movie_id = tm.id
  LEFT JOIN tags t ON t.id = mt.tag_id
性能要好得多。但我还有一个问题。最终目标是创建一种形式的可重用组件,如Postgres中的函数或ORM(如Rails的活动记录)中的命名查询,我可以根据自己的需要动态修改这些组件,例如:

  SELECT * FROM my_top_movies_with_tags() AS tm
  WHERE tm.country = 'USA' AND tm.year <= 1995
  LIMIT 10;
这给了我以后动态修改它的灵活性,但从性能角度看,这要糟糕得多

有没有其他我不知道的方法来实现我的目标

我的目标总结如下:

仅在有限的电影集而不是整个电影表上生成聚合数组_agg。 通过添加WHERE、ORDER和LIMIT语句保持可修改性。 表现很好。 用它来模拟极限怎么样


也请考虑在性能临界查询时使用CTE。

< P>可以将表单输入添加到临时表中,并使用该表进行筛选。

 CREATE TEMP TABLE temp_inputs
  (
     country VARCHAR(80),
     year int
  )
  ON COMMIT DELETE ROWS;


WITH top_movies AS (
    SELECT m.*
    FROM movies m
    ORDER BY m.name
    LIMIT 10
  )
  SELECT tm.*, array_agg(t.name) AS tags
  FROM tmovies tm, temp_inputs
  LEFT JOIN movies_tags mt ON mt.movie_id = tm.id
  LEFT JOIN tags t ON t.id = mt.tag_id
  and tm.country = temp_inputs.country AND tm.year <=  temp_inputs.year

谢谢你的这篇文章!ruw_数的使用非常有趣。我将对它进行一些实验,并将其与我从其他方法获得的基准进行比较。感谢您的输入。但我不明白这是如何改进我的查询的。这种过滤可以使用常规的where语句来完成。或者它是否以某种方式修改了公共表表达式?通过使用临时表,参数的运行时值将嵌入到查询中,因此不需要动态搜索。您是否可以对此进行详细说明,或者给我一个链接,以获取更多信息?这听起来很有趣,但我不确定工作流程到底应该如何工作。如何以及何时将值输入临时表?我是否必须在主语句中自动使用的临时表中定期插入一行?据我所知,oncommitdelete行在事务结束时删除临时表的内容。所以我必须将语句包装到事务中,以确保临时表在开始时为空吗?我只找到下面的链接,它可以给出一个想法。我建议您检查您的查询的执行计划。不幸的是,没有过时的查询优化解决方案。如果在每次搜索后关闭连接,则无需检查临时表。
SELECT * FROM (
    SELECT 
        m.*, 
        array_agg(t.name) AS tags,
        row_number() OVER(ORDER BY m.name) AS rownum
    FROM 
        movies m
        LEFT JOIN movies_tags mt ON mt.movie_id = m.id
        LEFT JOIN tags t ON t.id = mt.tag_id
    --There're must be a GROUP BY here
    ) AS tmp
WHERE rownum <= 10;
 CREATE TEMP TABLE temp_inputs
  (
     country VARCHAR(80),
     year int
  )
  ON COMMIT DELETE ROWS;


WITH top_movies AS (
    SELECT m.*
    FROM movies m
    ORDER BY m.name
    LIMIT 10
  )
  SELECT tm.*, array_agg(t.name) AS tags
  FROM tmovies tm, temp_inputs
  LEFT JOIN movies_tags mt ON mt.movie_id = tm.id
  LEFT JOIN tags t ON t.id = mt.tag_id
  and tm.country = temp_inputs.country AND tm.year <=  temp_inputs.year