Планы выполнения

waszkiewicz
Дата: 22.01.2013 14:47:18
Есть таблица
CREATE TABLE [dbo].[proc_packs](
	[id] [int] IDENTITY(1,1) NOT NULL,
	[po] [int] NULL,
	[prday] [datetime] NULL,
         ......
 CONSTRAINT [pk_proc_packs] PRIMARY KEY CLUSTERED 
(
	[id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

--Индекс
CREATE NONCLUSTERED INDEX [ix_proc_packs_prday] ON [dbo].[proc_packs] 
(
	[prday] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]


Что такого могло произойти, что при выполнении такого запроса
select sum(weight) 
,po
from proc_packs where prday>'20130102' 
group by po

В плане видим использование индекса ix_proc_packs_prday

а если prday>'20130101' - сканирование кластерного со всеми вытекающими - запрос выполняется больше 2-х минут (дальше ждать не стал)
PS Как планы опубликовать здесь?
SELECT @@VERSION
Microsoft SQL Server 2008 (SP2) - 10.0.4064.0 (X64) Feb 25 2011 13:56:11 Copyright (c) 1988-2008 Microsoft Corporation Enterprise Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)
Ennor Tiegael
Дата: 22.01.2013 14:53:28
waszkiewicz,

Во втором случае статистика говорит оптимизатору, что данных, подпадающих под условие слишком много, и лукап получится слишком дорогой.

Можно обновить статистику (и регулярно делать это в дальнейшем), а можно сделать покрывающий индекс, если запрос очень частый. Что-нибудь типа
(prday, po) include (weight)
waszkiewicz
Дата: 22.01.2013 15:07:19
данных за 20130101 нет вообще.
если указать where prday>'20121231' - та же ситуация - сканирование кластерного индекса.
Индексов на таблице и так много (не моя разработка) - навесить еще один - дорого.
select COUNT(id) from proc_packs

(No column name)
43126238

Пока на ум приходит только костыль с фильтрацией по предварительно полученному min(id)
waszkiewicz
Дата: 22.01.2013 15:12:22
Ennor Tiegael
waszkiewicz,

Во втором случае статистика говорит оптимизатору, что данных, подпадающих под условие слишком много, и лукап получится слишком дорогой.

Можно обновить статистику (и регулярно делать это в дальнейшем), а можно сделать покрывающий индекс, если запрос очень частый. Что-нибудь типа
(prday, po) include (weight)


Сегодня индекс перестроил - не помогает. Пока вот так вышел
from proc_packs with (index(ix_proc_packs_prday))
Гость333
Дата: 22.01.2013 15:22:37
waszkiewicz,

Покажите результат выполнения
dbcc show_statistics('dbo.proc_packs', 'ix_proc_packs_prday')
waszkiewicz
Дата: 22.01.2013 15:27:06
Последние 9 строк

RANGE_HI_KEY RANGE_ROWS EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
2012-12-08 00:00:00.000 118036,4 102249,6 2 59018,19
2012-12-12 00:00:00.000 181594,4 90220,21 3 60531,48
2012-12-19 00:00:00.000 211860,2 48117,45 6 35310,03
2012-12-27 00:00:00.000 223966,5 6014,681 7 31995,21
2013-01-05 00:00:00.000 129974,5 72176,17 6 21662,42
2013-01-13 00:00:00.000 233046,2 30073,4 6 38841,04
2013-01-20 00:00:00.000 172514,7 42102,77 6 28752,45
2013-01-21 00:00:00.000 0 6014,681 0 1
Гость333
Дата: 22.01.2013 15:56:40
waszkiewicz
данных за 20130101 нет вообще.

Но оптимизатор при построении плана запроса этого не знает:
waszkiewicz
RANGE_HI_KEY RANGE_ROWS EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
2012-12-27 00:00:00.000 223966.5 6014.681 7 31995.21
2013-01-05 00:00:00.000 129974.5 72176.17 6 21662.42

Я могу ошибаться, но, скорее всего, оптимизатор считает данные внутри интервала — равномерно распределёнными. То есть из 129974.5 записей — 4/9 будут считаться относящимися к 1, 2, 3 и 4 января, а 3/9 — к 2, 3 и 4 января. То есть оптимизатор будет считать, что запросу where prday>'20130102' надо обработать на 129974.5 * 1/9 = 14441,6 записей меньше, чем запросу where prday>'20130101'.

Чему равно Estimated Number of Rows при чтении из таблицы proc_packs в том и в другом плане выполнения?
waszkiewicz
Дата: 22.01.2013 16:10:58
833,181 и 833,138 (для случая с index_seek)
Гость333
Дата: 22.01.2013 17:04:19
waszkiewicz,

А для незахинтованных запросов?
waszkiewicz
Дата: 22.01.2013 17:23:38
Это именно для них. Для хинтованного - 833,166