SQL 窗口函数 - SELECT DISTINCT ORDER BY LIMIT
Posted
技术标签:
【中文标题】SQL 窗口函数 - SELECT DISTINCT ORDER BY LIMIT【英文标题】:SQL Window Functions - SELECT DISTINCT ORDER BY LIMIT 【发布时间】:2013-04-19 19:27:58 【问题描述】:我的 PostgreSQL 数据库中有这 3 个表:
艺术家: id、姓名 专辑: ID、标题、年份、艺术家 ID 歌曲: id、标题、album_id基本上每个艺人都有多张专辑,每张专辑都有多首歌曲。
我的查询正确返回了 25 个不同的艺术家 ID,他们的歌曲标题以“The”开头,按专辑年份排序:
SELECT id
FROM (
-- Remove the duplicate artists
SELECT DISTINCT ON (a.id) id, row
FROM (
-- Get all matching artists
-- This is slow because there is no limit
SELECT
artist.id,
row_number() OVER(ORDER BY album.year DESC) as row
FROM artist
LEFT JOIN album ON album.artist_id = artist.id
LEFT JOIN song ON song.album_id = album.id
WHERE song.title ilike 'The %'
ORDER BY album.year DESC
) as a
) as b
ORDER BY row
LIMIT 25
但是它速度慢且效率低,因为最里面的查询没有 LIMIT,因此它将搜索整个表以查找所有可能的匹配项。理想情况下,当找到 25 个不同的艺术家 ID 时,它会停止搜索。
可以重写或优化此查询以更快地执行吗?
我认为window functions 可以在这里加快速度,但我一直无法找出可行的方法。
谢谢!
【问题讨论】:
你看过查询的计划了吗?可以展示一下吗? 如果你在歌曲表中使用过滤器,你可以在这个关系中使用内连接,不是吗? 请阅读***.com/tags/postgresql-performance/info 并相应地更新您的帖子。 pg版本、查询计划等 【参考方案1】:select id, year
from (
SELECT DISTINCT ON (artist.id) artist.id, album.year
FROM artist
inner JOIN album ON album.artist_id = artist.id
inner JOIN song ON song.album_id = album.id
WHERE song.title ilike 'The %'
ORDER BY artist.id, album.year DESC
) s
order by year desc
LIMIT 25
当 ilike 表达式确实以 %
开头时,song.title
上的索引会有所帮助
【讨论】:
这个答案的另一个好处是外连接仍然是外连接。我以前没有注意到,但是,在最初的问题中,由于在 where 子句中引用了外连接表,它实际上变成了内连接。 此查询不会返回25 distinct artist.id's who have a song whose title begins with "The "
。它总是返回前 25 个艺术家 ID。
这需要 ORDER BY album.year -- 而不是 artist.id,因此是我的嵌套选择语句。子查询左连接很有趣,我会看看。
谢谢,这是一个重大改进。比我的查询快 27%。但我接受@Akash 的回答,因为它是一个单一的 SELECT 并且速度更快。【参考方案2】:
试试这个,应该比你当前的查询更快
SELECT
artist.id,
MAX( album.year ) as latest_album_date
FROM
artist
JOIN album ON album.artist_id = artist.id -- JOIN, not LEFT JOIN
JOIN song ON song.album_id = album.id -- Since you have song.title in WHERE clause, it makes no sense to make these as a LEFT JOIN
WHERE
song.title ilike 'The %'
GROUP BY
artist.id
ORDER BY
latest_album_date DESC
limit 25;
SQLFIDDLE
【讨论】:
group by
或 distinct
应该足够了。在此查询中无需同时使用两者。 group by
也将使用索引来删除重复项。
谢谢,这就是我一直在寻找的,现在看起来很明显。平均查询时间缩短 32%!【参考方案3】:
试试这个,
Select id, year
from (
SELECT DISTINCT ON (artist.id) artist.id, album.year
FROM artist
rightJOIN album ON album.artist_id = artist.id
left JOIN song ON song.album_id = album.id
WHERE song.title ilike 'The %'
ORDER BY artist.id, album.year DESC
) s
order by year desc
LIMIT 25
【讨论】:
以上是关于SQL 窗口函数 - SELECT DISTINCT ORDER BY LIMIT的主要内容,如果未能解决你的问题,请参考以下文章
Sql server - 窗口函数只能出现在 SELECT 或 ORDER BY 子句中
SQL 窗口函数 - SELECT DISTINCT ORDER BY LIMIT
从 SQL SELECT 中的子查询和 ROW_NUMBER 窗口函数生成“平均”列