как исправить производительность этого запроса на SQL Server Compact Edition 4 - PullRequest
3 голосов
/ 30 октября 2011

У меня есть следующий запрос SQL, который выполняется на SQL Server CE 4

SELECT [Join_ReleaseMinDatePost].[FK_MovieID]
  FROM ( 
          SELECT [FK_MovieID], MIN([DatePost]) AS [ReleaseMinDatePost] 
          FROM [Release] 
          GROUP BY [FK_MovieID] 
        ) [Join_ReleaseMinDatePost]
  INNER JOIN  
        ( 
          SELECT COUNT([ID]) AS [FolderCount], [FK_MovieID] 
          FROM [MovieFolder] 
          GROUP BY [FK_MovieID] 
        )  [Join_MovieFolder]
    ON [Join_MovieFolder].[FK_MovieID] = [Join_ReleaseMinDatePost].[FK_MovieID]

этот запрос занимает много времени, но если я изменяю часть

SELECT COUNT([ID]) AS [FolderCount], [FK_MovieID] FROM [MovieFolder] GROUP BY [FK_MovieID]

на

SELECT 1 AS [FolderCount], [FK_MovieID] FROM [MovieFolder]

Таким образом, полный запрос становится

SELECT [Join_ReleaseMinDatePost].[FK_MovieID]
FROM ( SELECT [FK_MovieID], MIN([DatePost]) AS [ReleaseMinDatePost] FROM [Release] GROUP BY [FK_MovieID] ) [Join_ReleaseMinDatePost]
INNER  JOIN  (SELECT 1 AS [FolderCount], [FK_MovieID] FROM [MovieFolder] ) [Join_MovieFolder]
ON [Join_MovieFolder].[FK_MovieID] = [Join_ReleaseMinDatePost].[FK_MovieID]

, тогда производительность становится очень высокой.
Проблема в том, что часть, которая была изменена, если она взята сама по себе, довольно быстрая.но по какой-то причине план выполнения первого запроса показывает, что «фактическое количество строк» ​​при сканировании индекса составляет 160 016, тогда как общее количество строк в таблице MovieFolder равно 2 192.и «Расчетное количество строк» ​​равно 2192.
, поэтому я думаю, что проблема заключается в количестве строк, но я не могу понять, почему все это испортилось.
любая помощь будет оценена :) спасибо

схема таблиц ниже

CREATE TABLE [Release] (
  [ID] int NOT NULL
, [FD_ForumID] int NOT NULL
, [FK_MovieID] int NULL
, [DatePost] datetime NULL
);
GO
ALTER TABLE [Release] ADD CONSTRAINT [PK__Release__0000000000000052] PRIMARY KEY ([ID]);
GO
CREATE INDEX [IX_Release_DatePost] ON [Release] ([DatePost] ASC);
GO
CREATE INDEX [IX_Release_FD_ForumID] ON [Release] ([FD_ForumID] ASC);
GO
CREATE INDEX [IX_Release_FK_MovieID] ON [Release] ([FK_MovieID] ASC);
GO
CREATE UNIQUE INDEX [UQ__Release__0000000000000057] ON [Release] ([ID] ASC);
GO

CREATE TABLE [MovieFolder] (
  [ID] int NOT NULL  IDENTITY (1,1)
, [Path] nvarchar(500) NOT NULL
, [FK_MovieID] int NULL
, [Seen] bit NULL
);
GO
ALTER TABLE [MovieFolder] ADD CONSTRAINT [PK_MovieFolder] PRIMARY KEY ([ID]);
GO
CREATE INDEX [IX_MovieFolder_FK_MovieID] ON [MovieFolder] ([FK_MovieID] ASC);
GO
CREATE INDEX [IX_MovieFolder_Seen] ON [MovieFolder] ([Seen] ASC);
GO
CREATE UNIQUE INDEX [UQ__MovieFolder__0000000000000019] ON [MovieFolder] ([ID] ASC);
GO
CREATE UNIQUE INDEX [UQ__MovieFolder__0000000000000020] ON [MovieFolder] ([Path] ASC);
GO

Ответы [ 3 ]

1 голос
/ 30 октября 2011

Я думаю, что вы столкнулись с проблемой коррелированного подзапроса . Часть запроса, с которой вы экспериментируете, является частью условия JOIN, поэтому она полностью оценивается для каждой потенциально совпадающей строки . Вы заставляете свой движок SQL выполнять второе «GROUP BY» для каждой строки, созданной предложением FROM. Таким образом, он читает 2192 строки, чтобы выполнить группировку для каждой строки, созданной предложением FROM.

Это говорит о том, что вы получаете 73 строки в группе предложений FROM (2192 * 73 = 160 016)

Когда вы изменяете его на SELECT 1, вы исключаете чтение таблицы сканирования для группировки.

0 голосов
/ 30 октября 2011

Я думаю, если обнаружил проблему.
, но я хотел бы, чтобы люди сказали мне, действительно ли это проблема.
Проблема в том, что 2 подзапроса создают некую временную таблицу (не знаю, какназовите его).
, но эти 2 временные таблицы не содержат кластеризованный индекс для [FK_MovieID].
, поэтому, когда внешнее объединение пытается присоединиться к ним, оно должно сканировать их несколько раз, и это, в основном, проблема.
сейчас, если я могу только это исправить?

0 голосов
/ 30 октября 2011

DaveE прав насчет проблемы с вашим коррелированным подзапросом. Когда возникают эти проблемы, вам часто нужно переосмыслить весь ваш запрос. Если что-то не получится, вы, вероятно, сможете сэкономить время на извлечение подзапроса во временную таблицу, например:

/* Declare in-memory temp table */
DECLARE @Join_MovieFolder TABLE ( 
     count INT,
     movieId INT )

 /* Insert data into temp table */
 INSERT INTO @Join_MovieFolder ( count, movieId ) 
 SELECT COUNT([ID]) AS [FolderCount], [FK_MovieID] 
          FROM [MovieFolder] 
          GROUP BY [FK_MovieID] 


 /* Inner join the temp table to avoid excessive sub-quering */
SELECT [Join_ReleaseMinDatePost].[FK_MovieID]
  FROM ( 
          SELECT [FK_MovieID], MIN([DatePost]) AS [ReleaseMinDatePost] 
          FROM [Release] 
          GROUP BY [FK_MovieID] 
        ) [Join_ReleaseMinDatePost]
  INNER JOIN @Join_MovieFolder 
    ON @Join_MovieFolder.movieId = [Join_ReleaseMinDatePost].[FK_MovieID]
...