Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 дорогой clustered index scan  [new]
monstrU
Member

Откуда: Москва
Сообщений: 1241
всем привет.
в нашем проекте мы чудили-чудили и начудили до долго работающих запросов.
в плане запроса раскопал довольно большой clustered index scan.
запрос вот такой
SELECT [t5].[message_id] AS [ID], [t5].[messageStatus_code] AS [code]
FROM (
    SELECT DISTINCT [t4].[message_id], [t4].[message_sourceId], [t4].[message_title], [t4].[message_authorId], [t4].[message_url], [t4].[message_text], [t4].[message_dateCreated], [t4].[message_dateUpdated], [t4].[message_dateCrawled], [t4].[message_dateInserted], [t4].[message_parentId], [t4].[message_threadId], [t4].[statusActual], [t4].[languageId], [t4].[likesCount], [t4].[messageStatus_code], [t4].[urgent], [t4].[spamExpectation], [t4].[branchesCode], [t4].[geoPlace], [t4].[isDurty], [t4].[commentators], [t4].[favorites], [t4].[duplicate_id]
    FROM (
        SELECT [t3].[message_id], [t3].[message_sourceId], [t3].[message_title], [t3].[message_authorId], [t3].[message_url], [t3].[message_text], [t3].[message_dateCreated], [t3].[message_dateUpdated], [t3].[message_dateCrawled], [t3].[message_dateInserted], [t3].[message_parentId], [t3].[message_threadId], [t3].[statusActual], [t3].[languageId], [t3].[likesCount], [t3].[messageStatus_code], [t3].[urgent], [t3].[spamExpectation], [t3].[branchesCode], [t3].[geoPlace], [t3].[isDurty], [t3].[commentators], [t3].[favorites], [t3].[duplicate_id]
        FROM (
            SELECT [t0].[message_id], [t0].[message_sourceId], [t0].[message_title], [t0].[message_authorId], [t0].[message_url], [t0].[message_text], [t0].[message_dateCreated], [t0].[message_dateUpdated], [t0].[message_dateCrawled], [t0].[message_dateInserted], [t0].[message_parentId], [t0].[message_threadId], [t0].[statusActual], [t0].[languageId], [t0].[likesCount], [t0].[messageStatus_code], [t0].[urgent], [t0].[spamExpectation], [t0].[branchesCode], [t0].[geoPlace], [t0].[isDurty], [t0].[commentators], [t0].[favorites], [t0].[duplicate_id]
            FROM [dbo].[Messages] AS [t0]
            WHERE ([t0].[message_dateInserted] < @p0) AND ([t0].[statusActual] IS NOT NULL) AND (([t0].[statusActual]) = 1) AND ([t0].[statusActual] = 1) AND (NOT ([t0].[message_threadId] IS NOT NULL))
            UNION
            SELECT [t2].[message_id], [t2].[message_sourceId], [t2].[message_title], [t2].[message_authorId], [t2].[message_url], [t2].[message_text], [t2].[message_dateCreated], [t2].[message_dateUpdated], [t2].[message_dateCrawled], [t2].[message_dateInserted], [t2].[message_parentId], [t2].[message_threadId], [t2].[statusActual], [t2].[languageId], [t2].[likesCount], [t2].[messageStatus_code], [t2].[urgent], [t2].[spamExpectation], [t2].[branchesCode], [t2].[geoPlace], [t2].[isDurty], [t2].[commentators], [t2].[favorites], [t2].[duplicate_id]
            FROM [dbo].[MessageGroups] AS [t1]
            [!----] INNER JOIN [dbo].[Messages] AS [t2] ON [t2].[message_id] = [t1].[mg_messageId][---!]
            WHERE ([t1].[mg_groupId]) = @p1
            ) AS [t3]
        ) AS [t4]
    ) AS [t5]
ORDER BY [t5].[message_dateCreated] DESC

как я понял, имеются затраты на сканирование столбца MessageId таблицы Messages.
символом [!----] я выделил место, где по-моем подозрению и возникают эти затраты

поле создано вот так

CREATE TABLE [dbo].[Messages](
	[message_id] [int] IDENTITY(1,1) NOT NULL,	
 CONSTRAINT [Messages_PK] PRIMARY KEY CLUSTERED 
(
	[message_id] ASC
	..........
)
) ON [PRIMARY]


вот сам ключ

ALTER TABLE [dbo].[Messages] ADD  CONSTRAINT [Messages_PK] PRIMARY KEY CLUSTERED 
(
	[message_id] ASC
)


какие меры можно принять в этом случае ?

К сообщению приложен файл. Размер - 19Kb
28 мар 14, 10:33    [15799106]     Ответить | Цитировать Сообщить модератору
 Re: дорогой clustered index scan  [new]
SomewhereSomehow
Member

Откуда: Moscow
Сообщений: 2480
Блог
monstrU,

Я бы посоветовал в первую очередь оптимизировать логику запроса.
Вы выбираете в итоге всего три поля два в селекте и сортировка. Вопрос - вам действительно нужно делать UNION, объединяя и отбирая уникальные записи по куче полей? Оптимизатор, конечно, умеет исключать лишние поля, если они не используются во внешнем запросе, но тут исключать их нельзя, т.к. они определяют число записей после объединения.
+ форматированный текст

SELECT 
	[t5].[message_id] AS [ID], 
	[t5].[messageStatus_code] AS [code]
FROM 
	(
		SELECT DISTINCT 
			[t4].[message_id], 
			[t4].[message_sourceId], 
			[t4].[message_title], 
			[t4].[message_authorId], 
			[t4].[message_url], 
			[t4].[message_text],
			[t4].[message_dateCreated], 
			[t4].[message_dateUpdated], 
			[t4].[message_dateCrawled], 
			[t4].[message_dateInserted], 
			[t4].[message_parentId], 
			[t4].[message_threadId], 
			[t4].[statusActual], 
			[t4].[languageId], 
			[t4].[likesCount], 
			[t4].[messageStatus_code], 
			[t4].[urgent], 
			[t4].[spamExpectation], 
			[t4].[branchesCode], 
			[t4].[geoPlace], 
			[t4].[isDurty], 
			[t4].[commentators], 
			[t4].[favorites], 
			[t4].[duplicate_id]
		FROM (
			SELECT 
				[t3].[message_id], 
				[t3].[message_sourceId], 
				[t3].[message_title], 
				[t3].[message_authorId], 
				[t3].[message_url],
				[t3].[message_text], 
				[t3].[message_dateCreated], 
				[t3].[message_dateUpdated], 
				[t3].[message_dateCrawled], 
				[t3].[message_dateInserted], 
				[t3].[message_parentId], 
				[t3].[message_threadId], 
				[t3].[statusActual], 
				[t3].[languageId], 
				[t3].[likesCount], 
				[t3].[messageStatus_code], 
				[t3].[urgent], 
				[t3].[spamExpectation], 
				[t3].[branchesCode], 
				[t3].[geoPlace], 
				[t3].[isDurty], 
				[t3].[commentators], 
				[t3].[favorites], 
				[t3].[duplicate_id]
			FROM 
			(
				SELECT 
					[t0].[message_id], 
					[t0].[message_sourceId], 
					[t0].[message_title], 
					[t0].[message_authorId], 
					[t0].[message_url], 
					[t0].[message_text], 
					[t0].[message_dateCreated], 
					[t0].[message_dateUpdated], 
					[t0].[message_dateCrawled], 
					[t0].[message_dateInserted], 
					[t0].[message_parentId], 
					[t0].[message_threadId], 
					[t0].[statusActual], 
					[t0].[languageId], 
					[t0].[likesCount], 
					[t0].[messageStatus_code], 
					[t0].[urgent], 
					[t0].[spamExpectation], 
					[t0].[branchesCode], 
					[t0].[geoPlace], 
					[t0].[isDurty], 
					[t0].[commentators], 
					[t0].[favorites], 
					[t0].[duplicate_id]
				FROM 
					[dbo].[Messages] AS [t0]
				WHERE 
					([t0].[message_dateInserted] < @p0) AND 
					([t0].[statusActual] IS NOT NULL) AND 
					(([t0].[statusActual]) = 1) AND ([t0].[statusActual] = 1) AND 
					(NOT ([t0].[message_threadId] IS NOT NULL))
				UNION
				SELECT 
					[t2].[message_id], 
					[t2].[message_sourceId], 
					[t2].[message_title], 
					[t2].[message_authorId],
					[t2].[message_url], 
					[t2].[message_text], 
					[t2].[message_dateCreated], 
					[t2].[message_dateUpdated], 
					[t2].[message_dateCrawled], 
					[t2].[message_dateInserted], 
					[t2].[message_parentId], 
					[t2].[message_threadId], 
					[t2].[statusActual], 
					[t2].[languageId], 
					[t2].[likesCount], 
					[t2].[messageStatus_code], 
					[t2].[urgent], 
					[t2].[spamExpectation], 
					[t2].[branchesCode], 
					[t2].[geoPlace], 
					[t2].[isDurty], 
					[t2].[commentators], 
					[t2].[favorites], 
					[t2].[duplicate_id]
				FROM 
					[dbo].[MessageGroups] AS [t1]
					INNER JOIN [dbo].[Messages] AS [t2] ON [t2].[message_id] = [t1].[mg_messageId]
				WHERE 
					([t1].[mg_groupId]) = @p1
            ) AS [t3]
        ) AS [t4]
    ) AS [t5]
ORDER BY 
	[t5].[message_dateCreated] DESC

Нужны по-сути только выделенные поля, зачем все остальные выбираются и с ними делаются дорогостоящие операции UNION?

Такие вложенные запросы любят генерировать разные ORM, типа EF и иже с ними. Они могут генерировать текст не очень интеллектуально.

Я бы начал с того, что подумал, как бы я написал этот запрос без ORM, какая была бы логика, что мне нужно найти, какие поля выбрать, и т.д. После этого, попытаться научить ORM генерировать правильный запрос. Если это рукописный запрос, то остается просто понять логику и переписать его.

Что касается плана - план надо выкладывать файлом .sqlplan а не картинкой. По картинке трудно судить, кроме самых грубых прикидок. Гораздо больше сканирования мне не нравятся, например сортировки, но трудно сказать не видя деталей, например о точном числе строк, полях сортировки и т.д. Подозреваю, что сортировка по множеству столбцов может вызывать spill в tempdb, проверьте это в Profiler - Sort Warnings (если сервер ниже 2012), если 2012 - то должно отображаться в действительном плане как предупреждение. Опять же не видно, какой это план, оценочный или нет, вроде судя по наличию панели результатов действительный, но всякое может быть. Короче, картинка ни о чем, почти.
28 мар 14, 11:19    [15799446]     Ответить | Цитировать Сообщить модератору
 Re: дорогой clustered index scan  [new]
tomcat2
Member

Откуда:
Сообщений: 69
Это не индекс читает а саму таблицу. Много полей берете из Messages, на их чтение идет основное время, возможно эта Messages сильно фрагментирована.
28 мар 14, 11:24    [15799497]     Ответить | Цитировать Сообщить модератору
 Re: дорогой clustered index scan  [new]
invm
Member

Откуда: Москва
Сообщений: 9836
Добавлю: distinct на том же наборе столбцов, что и предшествующий union, вообще не имеет смысла.
28 мар 14, 11:25    [15799507]     Ответить | Цитировать Сообщить модератору
 Re: дорогой clustered index scan  [new]
aleks2
Guest
invm
Добавлю: distinct на том же наборе столбцов, что и предшествующий union, вообще не имеет смысла.

Но самая то засада, что сервер об этом не знает.
28 мар 14, 11:29    [15799563]     Ответить | Цитировать Сообщить модератору
 Re: дорогой clustered index scan  [new]
SomewhereSomehow
Member

Откуда: Moscow
Сообщений: 2480
Блог
aleks2
Но самая то засада, что сервер об этом не знает.

Не всегда, конечно, но в целом, он умеет такое распознавать.
одинаковые планы:
+
select distinct number
from
(
select number from master..spt_values
union
select number from master..spt_values
) a

select number from master..spt_values
union
select number from master..spt_values

В плане ТС я не вижу кроме Merge Union каких-то операторов, которые бы distinct реализовали, агрегаций там или distinct sort, так что, скорее всего, сервер выкидывает этот лишний дистинкт.
28 мар 14, 12:45    [15800125]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить