Как превратить JOINS в подзапросы, не нарушая логику SQL - PullRequest
0 голосов
/ 14 апреля 2019

У меня проблемы с производительностью при использовании нескольких объединений в T-SQL, и если кто-то может помочь мне превратить эти объединения в подзапросы, было бы неплохо.

Всякий раз, когда я пытаюсь изменить объединение в подзапрос, ятеряю объявление имени для конкретной таблицы.Например, если я пытаюсь превратить объединение альбома (которое является первым соединением в приведенном ниже коде) в подзапрос, я теряю псевдоним «AS a» и «Альбом a.Title AS» перестал работать, поэтому я понятия не имею, как этобудет сделано.Если кто-нибудь даст мне пример того, как он должен работать в одном из случаев, я полагаю, что смогу восстановить все из них.

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

Ответы [ 2 ]

1 голос
/ 14 апреля 2019

Превратить объединение в подзапрос может быть не лучшим решением

при условии, что у вас уже есть индекс для внешнего ключа для каждой повторно используемой таблицы

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 )
0 голосов
/ 14 апреля 2019

Что за подзапрос вы имеете в виду?Что-то вроде:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...