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

Откуда:
Сообщений: 143
Итак в оракле есть хинты index_asc и index_desc, они меня здорово выручали.

Есть запрос (реальный пример не могу дать)

select top 1 *
from tab1
where col1 = x 
  exist (select 1
                    from tab where = ...)
   and .....
order by date1 desc , order by date2 desc


есть индекс (col1, date1, date2)
план рисуется такой, что проходит соединение , потом сортировка результата по полям (сортировка в плане занимает 80%). Вот хочу попробовать заставить сканить индекс (по статистике в индексе прочитается 1-2 записи)
14 мар 13, 14:30    [14047772]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
tpg
Member

Откуда: Novosibirsk
Сообщений: 23902
CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name
ON <object> ( column [ ASC | DESC ] [ ,...n ] )
[ INCLUDE ( column_name [ ,...n ] ) ]
[ WHERE <filter_predicate> ]
[ WITH ( <relational_index_option> [ ,...n ] ) ]
[ ON { partition_scheme_name ( column_name )
| filegroup_name
| default
}
]
[ FILESTREAM_ON { filestream_filegroup_name | partition_scheme_name | "NULL" } ]

[ ; ]
14 мар 13, 14:33    [14047794]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
ArtMan
Member

Откуда:
Сообщений: 143
Несколько запросов, однни по возрастанию, другой по убыванию.... Нужна помощь именно в хинте.
14 мар 13, 14:35    [14047806]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
ArtMan
Member

Откуда:
Сообщений: 143
Мне нужно двигаться по определенному направлению индекса.
14 мар 13, 14:37    [14047817]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
Мистер Хенки
Member

Откуда: канализация
Сообщений: 6615
а мне казалось, что sql server, по крайней мере при сортировке по одному полю умеет сам выбирать направление движения и никаких хинтов не надо. Как с двумя не знаю, надо попробовать, главное, наверное, чтобы поля в данном случае сортировались однонаправленно в индексе.
14 мар 13, 14:51    [14047905]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
ArtMan
Member

Откуда:
Сообщений: 143
Проблема в оптимизаторе, он не хочет бежать по индексу с нужной сортировкой по дате, а сначала делает соединение, а потом сортирует результат.
14 мар 13, 15:01    [14047972]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
Гость333
Member

Откуда:
Сообщений: 3683
ArtMan
Есть запрос (реальный пример не могу дать)

Ну дайте тогда вымышленный пример. Я вот не смог воспроизвести то, о чём вы пишете.

Подготовка таблицы:
use tempdb;
go
create table tab1(id int identity primary key, col1 int, date1 datetime, date2 datetime);
create index i_tab1 on tab1 (col1, date1, date2);
go

Смотрим план запроса, похожего на ваш:
set showplan_text on;
go
declare @x int;

select top 1 *
from dbo.index_test t
where t.col1 = @x 
  and exists (select 1
              from sys.tables st
              where st.object_id = t.col1)
order by t.date1 desc , t.date2 desc;
go
set showplan_text off;
go

  |--Top(TOP EXPRESSION:((1)))
       |--Nested Loops(Left Semi Join)
            |--Index Seek(OBJECT:([tempdb].[dbo].[tab1].[i_tab1] AS [t]), SEEK:([t].[col1]=[@x]) ORDERED BACKWARD)
            |--Filter(WHERE:(has_access('CO',[tempdb].[sys].[sysschobjs].[id] as [o].[id])=(1)))
                 |--Clustered Index Seek(OBJECT:([tempdb].[sys].[sysschobjs].[clst] ...)

Никакой сортировки не наблюдается.
14 мар 13, 15:06    [14047995]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
ArtMan
Member

Откуда:
Сообщений: 143
Параллельно делал с другими примерами, засада с вычисляемыми полями... Не знаю почему, оптимизатор берет базовое поле для вычисляемого, хотя вычисляемое PERSISTED. Мало того, если базового поля нет в include, то обращение идет к кластерному индексу.
14 мар 13, 15:57    [14048323]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
Гость333
Member

Откуда:
Сообщений: 3683
Ну, типа, пора бы пример уже привести.
14 мар 13, 16:04    [14048360]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
ArtMan
Member

Откуда:
Сообщений: 143
На почту скину..., тут не буду размещать.
14 мар 13, 16:23    [14048519]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
ArtMan
Member

Откуда:
Сообщений: 143
Индекс
REATE NONCLUSTERED INDEX [IX_RW_SHIPMENT_FACT_CARNUM_DATE_S]
ON [dbo].[RW_SHIPMENT_FACT]
(
 [CAR_NUMBER] , [DATE_S] , [date_r_f01] , [HIDE] , [IsManualHide] , [CONT_PREFIX] , [CONT_NUMBER] 
)
INCLUDE (
 .....
)


поле
[date_r_f01] AS (isnull([date_r],CONVERT([datetime],'9999-12-31',(126)))) PERSISTED NOT NULL)


запрос
select ...
order by date_s asc


 |--Parallelism(Gather Streams)
       |--Nested Loops(Left Outer Join, OUTER REFERENCES:([f].[CAR_NUMBER], [f].[DATE_S]))
            |--Index Seek(OBJECT:([iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[IX_RW_SHIPMENT_FACT_DATE_S] AS [f]), SEEK:([f].[DATE_S] >= [@sd] AND [f].[DATE_S] < dateadd(day,(1),[@ed])) ORDERED FORWARD)
            |--Compute Scalar(DEFINE:([Expr1007]=[iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[ID] as [t].[ID]))
                 |--Top(TOP EXPRESSION:((1)))
                      |--Nested Loops(Left Semi Join, WHERE:([iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[ETSNG] as [t].[ETSNG]=[iasSetr_test].[dbo].[qCargo].[code] as [cgo].[code]))
                           |--Index Seek(OBJECT:([iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[IX_RW_SHIPMENT_FACT_CARNUM_DATE_S] AS [t]), SEEK:([t].[CAR_NUMBER]=[iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[CAR_NUMBER] as [f].[CAR_NUMBER] AND [t].[DATE_S] < [iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[DATE_S] as [f].[DATE_S]),  WHERE:([iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[CONT_NUMBER] as [t].[CONT_NUMBER] IS NULL AND [iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[CONT_PREFIX] as [t].[CONT_PREFIX] IS NULL AND CASE WHEN [iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[IsManualHide] as [t].[IsManualHide] IS NOT NULL THEN CONVERT_IMPLICIT(int,[iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[IsManualHide] as [t].[IsManualHide],0) ELSE CASE WHEN [iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[HIDE] as [t].[HIDE] IS NOT NULL THEN CONVERT_IMPLICIT(int,[iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[HIDE] as [t].[HIDE],0) ELSE (0) END END=(0)) ORDERED FORWARD)
                           |--Table Spool
                                |--Index Scan(OBJECT:([iasSetr_test].[dbo].[qCargo].[IX_qCargo_CODE_EMPTY] AS [cgo]),  WHERE:([iasSetr_test].[dbo].[qCargo].[IS_EMPTY] as [cgo].[IS_EMPTY]=(1)))





в запросе меняем сортировку
order by t.date_s asc, t.date_r_f01 asc

получаем план
 |--Parallelism(Gather Streams)
       |--Nested Loops(Left Outer Join, OUTER REFERENCES:([f].[CAR_NUMBER], [f].[DATE_S]))
            |--Index Seek(OBJECT:([iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[IX_RW_SHIPMENT_FACT_DATE_S] AS [f]), SEEK:([f].[DATE_S] >= [@sd] AND [f].[DATE_S] < dateadd(day,(1),[@ed])) ORDERED FORWARD)
            |--Compute Scalar(DEFINE:([Expr1007]=[iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[ID] as [t].[ID]))
                 |--Sort(TOP 1, ORDER BY:([t].[DATE_S] ASC, [t].[date_r_f01] ASC))
                      |--Compute Scalar(DEFINE:([t].[date_r_f01]=isnull([iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[DATE_R] as [t].[DATE_R],'9999-12-31 00:00:00.000')))
                           |--Nested Loops(Left Semi Join, WHERE:([iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[ETSNG] as [t].[ETSNG]=[iasSetr_test].[dbo].[qCargo].[code] as [cgo].[code]))
                                |--Index Seek(OBJECT:([iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[IX_RW_SHIPMENT_FACT_CARNUM_DATE_S] AS [t]), SEEK:([t].[CAR_NUMBER]=[iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[CAR_NUMBER] as [f].[CAR_NUMBER] AND [t].[DATE_S] < [iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[DATE_S] as [f].[DATE_S]),  WHERE:([iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[CONT_NUMBER] as [t].[CONT_NUMBER] IS NULL AND [iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[CONT_PREFIX] as [t].[CONT_PREFIX] IS NULL AND CASE WHEN [iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[IsManualHide] as [t].[IsManualHide] IS NOT NULL THEN CONVERT_IMPLICIT(int,[iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[IsManualHide] as [t].[IsManualHide],0) ELSE CASE WHEN [iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[HIDE] as [t].[HIDE] IS NOT NULL THEN CONVERT_IMPLICIT(int,[iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[HIDE] as [t].[HIDE],0) ELSE (0) END END=(0)) ORDERED FORWARD)
                                |--Table Spool
                                     |--Index Scan(OBJECT:([iasSetr_test].[dbo].[qCargo].[IX_qCargo_CODE_EMPTY] AS [cgo]),  WHERE:([iasSetr_test].[dbo].[qCargo].[IS_EMPTY] as [cgo].[IS_EMPTY]=(1)))



План не должен меняться
14 мар 13, 16:45    [14048697]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
WarAnt
Member

Откуда: Питер
Сообщений: 2423
ArtMan,

автор
План не должен меняться

Кому не должен?


Вы не изменили сортировку, а добавили новое условие,

было
order by date_s asc

стало
order by t.date_s asc, t.date_r_f01 asc


что естественно повело за собой новый пункт плана
Compute Scalar(DEFINE:([t].[date_r_f01]=isnull([iasSetr_test].[dbo].[RW_SHIPMENT_FACT].[DATE_R] as [t].[DATE_R],'9999-12-31 00:00:00.000')))
что тут непонятного?
14 мар 13, 17:25    [14048915]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
ArtMan
Member

Откуда:
Сообщений: 143
Новое поле входит в индекс, по которому и идет скан.... там же все отсортировано
14 мар 13, 17:32    [14048951]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
daw
Member

Откуда: Муром -> Москва
Сообщений: 7381
> что тут непонятного?

ммм, а чего это date_r_f01 вдруг вычисляться начало? оно же в индексе - том самом, который в запросе используется.

мне вот, правда, повторить такое не удалось.
14 мар 13, 17:33    [14048955]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
Гость333
Member

Откуда:
Сообщений: 3683
daw
мне вот, правда, повторить такое не удалось.

Мне тоже. Видимо, и не удастся, пока ТС не выложит полноценный пример вместо неких отрывков. Если реальный код выкладывать нельзя, то можно обезличить таблицы, назвав столбцы A, B, C, D и т.д.
14 мар 13, 17:46    [14049018]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
ОперацияПингвин
Member

Откуда:
Сообщений: 648
Блог
Не ваш случай ?
15 мар 13, 00:00    [14050185]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
ОперацияПингвин
Member

Откуда:
Сообщений: 648
Блог
Хотя тут проблема с типом datetime

[date_r_f01] AS (CONVERT([binary](8),isnull([date_r],CONVERT([datetime],'9999-12-31',(126))))) PERSISTED NOT NULL,

Если такое поле сделать, то и индекс будет использоваться и сортировка такой же останется
15 мар 13, 02:20    [14050378]     Ответить | Цитировать Сообщить модератору
 Re: Сканировать индекс в определенном направлении  [new]
ArtMan
Member

Откуда:
Сообщений: 143
Всем спасибо. Разобрался, закоментил хинт
force order
, без него план остался прежним, хотя не понимаю почему с хинтом добавилась сортировка.
15 мар 13, 10:41    [14051298]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить