如何在不破坏SQL逻辑的情况下将JOINS转换为子查询
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在不破坏SQL逻辑的情况下将JOINS转换为子查询相关的知识,希望对你有一定的参考价值。
我在T-SQL中使用多个连接时遇到了性能问题,如果有人可以帮助我将这些连接转换为子查询,那就太好了。
每当我尝试将连接更改为子查询时,我都会丢失特定表的名称声明。例如,如果我尝试将Album join(这是下面代码的第一个连接)转换为子查询,我将失去别名“AS a”并且“a.Title AS Album”停止工作,所以我不知道这是怎么回事会做的。如果有人给我一个例子,它应该如何适用于其中一个案例,我想我将能够重建所有这些案例。
SQL
SELECT
t.TrackId,
t.[Name] AS Track,
a.Title AS Album,
aa.[Name] AS Artist,
p.[Name] AS Playlist,
m.[Name] AS MediaType,
il.UnitPrice AS InvoicePrice,
CONCAT(c.FirstName, ' ', c.LastName) AS CustomerName,
CONCAT(e.FirstName, ' ', e.LastName) AS ResponsibleEmployeeName
FROM dbo.Track AS t
INNER JOIN dbo.Album AS a
ON t.AlbumId = a.AlbumId
INNER JOIN dbo.Artist AS aa
ON a.ArtistId = aa.ArtistId
INNER JOIN dbo.PlaylistTrack AS plt
ON t.TrackId = plt.TrackId
INNER JOIN dbo.Playlist AS p
ON p.PlaylistId = plt.PlaylistId
INNER JOIN dbo.MediaType AS m
ON t.MediaTypeId = m.MediaTypeId
INNER JOIN dbo.InvoiceLine AS il
ON t.TrackId = il.TrackId
INNER JOIN dbo.Invoice AS i
ON il.InvoiceId = i.InvoiceId
INNER JOIN dbo.Customer AS c
ON i.CustomerId = c.CustomerId
INNER JOIN dbo.Employee AS e
ON c.SupportRepId = e.EmployeeId
WHERE m.[Name] LIKE '%audio%'
ORDER BY t.[Name] ASC
你的意思是什么样的子查询?就像是:
SELECT t.TrackId,
t.[Name] AS Track,
(SELECT title FROM dbo.Album WHERE AlbumId = t.AlbumId) AS AlbumTitle
如果你删除Album
的连接,那就不行了,因为你需要专辑参考才能找到艺术家。如果要加入子查询,可以执行此操作,并保留别名:
SELECT
t.TrackId,
t.[Name] AS Track,
a.Title AS Album,
aa.[Name] AS Artist,
p.[Name] AS Playlist,
m.[Name] AS MediaType,
il.UnitPrice AS InvoicePrice,
CONCAT(c.FirstName, ' ', c.LastName) AS CustomerName,
CONCAT(e.FirstName, ' ', e.LastName) AS ResponsibleEmployeeName
FROM dbo.Track AS t
INNER JOIN (SELECT * FROM dbo.Album) AS a
ON t.AlbumId = a.AlbumId
-- rest of joins
但从逻辑上讲,这与您现在完全相同,并且查询优化器生成的计划没有区别。即使这样:
SELECT
t.TrackId,
t.[Name] AS Track,
aa.Title AS Album, -- note change here
aa.[Name] AS Artist,
p.[Name] AS Playlist,
m.[Name] AS MediaType,
il.UnitPrice AS InvoicePrice,
CONCAT(c.FirstName, ' ', c.LastName) AS CustomerName,
CONCAT(e.FirstName, ' ', e.LastName) AS ResponsibleEmployeeName
FROM dbo.Track AS t
INNER JOIN (SELECT alb.Title
, art.Name
, alb.AlbumId
FROM dbo.Album alb
INNER JOIN dbo.Artist art
ON art.ArtistId = alb.ArtistID) AS aa
ON t.AlbumId = aa.AlbumId
INNER JOIN dbo.PlaylistTrack AS plt
ON t.TrackId = plt.TrackId
-- rest of them
将产生完全相同的计划。我们可能已经将Album
Artist
连接移动到一个连接的子查询,但实质上,它仍然是相同的东西 - 内部连接。
没有这样的事情会对你的表现有所帮助。可能对您有帮助的是在这些表上创建索引。如果这是您执行的查询类型,您还可以创建索引视图,如:
CREATE VIEW BoughtTracks
WITH SCHEMABINDING
AS
SELECT
il.InvoiceLineId, -- I'm guessing here, we need a unique ID
t.TrackId,
t.[Name] AS Track,
a.Title AS Album,
aa.[Name] AS Artist,
p.[Name] AS Playlist,
m.[Name] AS MediaType,
il.UnitPrice AS InvoicePrice,
CONCAT(c.FirstName, ' ', c.LastName) AS CustomerName,
CONCAT(e.FirstName, ' ', e.LastName) AS ResponsibleEmployeeName
FROM dbo.Track AS t
INNER JOIN dbo.Album AS a
ON t.AlbumId = a.AlbumId
INNER JOIN dbo.Artist AS aa
ON a.ArtistId = aa.ArtistId
INNER JOIN dbo.PlaylistTrack AS plt
ON t.TrackId = plt.TrackId
INNER JOIN dbo.Playlist AS p
ON p.PlaylistId = plt.PlaylistId
INNER JOIN dbo.MediaType AS m
ON t.MediaTypeId = m.MediaTypeId
INNER JOIN dbo.InvoiceLine AS il
ON t.TrackId = il.TrackId
INNER JOIN dbo.Invoice AS i
ON il.InvoiceId = i.InvoiceId
INNER JOIN dbo.Customer AS c
ON i.CustomerId = c.CustomerId
INNER JOIN dbo.Employee AS e
ON c.SupportRepId = e.EmployeeId
WHERE m.[Name] LIKE '%audio%'
CREATE UNIQUE CLUSTERED INDEX ux ON BoughtTracks (InvoiceLineId);
这将减慢对这些表的插入,但在BoughtTracks
上选择将很快(您还可以在该视图上创建其他索引),例如:
SELECT *
FROM BoughtTracks WITH (NOEXPAND) -- NOEXPAND is important
WHERE CustomerName = 'Joe Smith'
可以执行比当前查询更快的数量级,具体取决于数据的大小。特别是如果你在它上面创建一个索引
CREATE INDEX ix_CustomerName ON BoughtTracks (CustomerName)
INCLUDE (...) -- maybe include some columns you know you will need when querying for CustomerName
WHERE (...) -- maybe there are alsways accompanying predicates when querying for CustomerName
在子查询中转换连接可能不是最佳解决方案
假设您已经拥有每个零售表的外键索引
table Artist index on column (ArtistId)
table PlaylistTrack index on column (TrackId)
table Playlist index on column (PlaylistId)
table MediaType index on column ( MediaTypeId )
.....
为了性能,请确保您有索引
table track a composite index on column (AlbumId, TrackId, MediaTypeId )
table Album a cmposite index on column ( AlbumId, ArtistId )
以上是关于如何在不破坏SQL逻辑的情况下将JOINS转换为子查询的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用数据透视的情况下将行转换或转置为 SQL 中的列?
如何在不破坏滚动功能的情况下将 UIImage 添加到 UIScrollView?