优化连接查询,需要“过滤”不同的
Posted
技术标签:
【中文标题】优化连接查询,需要“过滤”不同的【英文标题】:Optimize join query with need to "filter" for distinct 【发布时间】:2021-05-16 15:52:30 【问题描述】:我想知道我还能优化多少相对简单的查询。为了抽象,我只有两个表,albums
,以专辑 ID 和专辑标题,另一个是 albums_genre
,以专辑 ID 和专辑类型为列。
我的查询如下:
SELECT DISTINCT album_title
from albums
INNER JOIN albums_genre
ON albums.album_id = albums_genre.album_id AND (genre = 'Metal' OR genre = 'Jazz')
对我来说问题是,在albums
表中,1 id 可能与多个专辑标题匹配,我正在尝试找到一种方法来减少 distinct 所需的时间,因为它需要一半以上的整体时间。我正在使用 Microsoft DB。
提前感谢大家!
【问题讨论】:
你为什么要distinct
ing,也许你的join
应该是exists
?也许genre
过滤器可以转换为union all
,但是如果没有关于索引的信息就很难说。为了获得适当的性能帮助,您需要提供完整查询、表和索引定义(最好是create/insert
语句),并通过brentozar.com/pastetheplan共享查询计划
您的餐桌设置听起来不合理。您的专辑表应该有一个专辑 ID、专辑名称,然后还有其他 ID,如流派 ID、艺术家 ID 等。第二个表“album_genres”将只有一个专辑流派 ID 和与这些流派 ID 一起使用的描述。换句话说,每个表都应该避免重复信息。通过将 album_ID 放入您的流派表中,流派表最终将重复显示相同的流派信息。那是不正确的设计。您可能会在此处阅读“3NF”=guru99.com/database-normalization.html
只需在流派列上放一个索引就可以了
仅供参考,“Microsoft DB”可能是 SQL Server 或 MS Access - 有助于明确。
【参考方案1】:
一个更优化的方法是使用exists
而不是 join 用于您的案例场景,您也可以使用 in
而不是 Or 来检查列中的多个值:
SELECT album_title
from albums a
where exists (
select 1 from albums_genre g
where a.album_id = g.album_id
and genre in ('Metal', 'Jazz')
)
【讨论】:
【参考方案2】:第一步是使用exists
编写查询:
SELECT a.album_title
FROM albums a
WHERE EXISTS (SELECT 1
FROM albums_genre ag
WHERE ag.album_id = a.album_id AND
ag.genre IN ('Metal', 'Jazz')
);
然后,为了提高性能,您需要在albums_genre(album_id, genre)
上建立索引。仅在 (album_id)
上的索引可能也足够好。
请注意,性能提升来自于删除外部查询中的聚合/不同的删除。
【讨论】:
感谢您的回答。我试过你的查询,它确实快得多(大约 50%),但与我原来的查询相比,它给了我更多的结果。它给了我超过 20k 行而不是 19742 行。在albums
表中,存在重复的标题(相同的标题,不同的专辑 ID),我认为这是导致问题的原因,你有任何想法如何改进查询?
@AndreasTzalakas。 . .我认为这产生了正确的结果,因为它为每个album_id
产生了一个单独的行。但是,如果您真的认为album_title
s 是独一无二的,您可以使用select distinct a.album_title
。【参考方案3】:
最初查询速度变慢是在“或”上,将“或”转换为子查询,见下文。而不是不同的使用组
SELECT album_title
from albums
INNER JOIN (select album_id from albums_genre where genre in ('Metal'
,'Jazz'))albums_genre
ON albums.album_id = albums_genre.album_id
group by album_title
【讨论】:
以上是关于优化连接查询,需要“过滤”不同的的主要内容,如果未能解决你的问题,请参考以下文章