Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Sybase ASA, ASE, IQ [игнор отключен] [закрыт для гостей] / План запроса в пакете и без / 20 сообщений из 20, страница 1 из 1
02.06.2011, 19:41
    #37292269
LelikB
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
Adaptive Server Enterprise/12.5.4/EBF

Вопрос больше теоретический.
Есть некий пакет в котором во временную таблицу с индексами вставляются данные (около 90000 строк), затем идет серия апдейтов этих данных.
insert #Temp...
update #Temp...
update #Temp...
update #Temp...

Так вот, обнаружилась интересная вещь: если выполнять каждый запрос последовательно, то оптимизатор корректно обнаруживает нужный индекс, все работает быстро. А если выполнить все в одном пакете, то на одном из запросов идет table scan. Если указать нужный индекс хинтом, то проблем не возникает.
Почему так происходит? Ведь данные и в первом и во втором случае в таблице одни и те же.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
create table #Card 
(
  CardID         numeric( 15 , 0 )
 ,ResourceID     numeric( 15 , 0 ) null
 ,StateOrder     int           null  
 ,IsActive       bit   
 ,IsNew          bit
 ,CrdGroup       smallint      null 
 ,CardRole       smallint           
 ,isMain         smallint
 ,DateExpiration smalldatetime
 ,MidRest        numeric( 18 , 2 ) 
)

create clustered index i1 on #Card(CardID)
create index i2 on #Card(ResourceID, CardRole)
Запрос:

Код: plaintext
1.
2.
3.
4.
5.
6.
update #Card
set isMain =  1 
where isActive= 0 
  and not exists (select  1  from #Card c1  (index i2)       --если индекс не указать, будет Table Scan  
                 where #Card.ResourceID = c1.ResourceID
                   and isActive =  1 )
...
Рейтинг: 0 / 0
02.06.2011, 19:52
    #37292285
LelikB
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
План при выполнении всего пакета (без хинта с индеком).
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
QUERY PLAN FOR STATEMENT 11 (at line 77).
    STEP 1
        The type of query is UPDATE.
        The update mode is deferred.
        FROM TABLE
            #Card
        Nested iteration.
        Table Scan.
        Forward scan.
        Positioning at start of table.
        Run subquery 1 (at nesting level 1).
        Using I/O Size 8 Kbytes for data pages.
        With LRU Buffer Replacement Strategy for data pages.
        TO TABLE
            #Card
        Using I/O Size 8 Kbytes for data pages.
    STEP 1
NESTING LEVEL 1 SUBQUERIES FOR STATEMENT 11.
  QUERY PLAN FOR SUBQUERY 1 (at nesting level 1 and at line 80).
    Correlated Subquery.
    Subquery under an EXISTS predicate.
    STEP 1
        The type of query is SELECT.
        Evaluate Ungrouped ANY AGGREGATE.
        FROM TABLE
            #Card
            c1
        EXISTS TABLE : nested iteration.
        Table Scan.
        Forward scan.
        Positioning at start of table.
        Using I/O Size 8 Kbytes for data pages.
        With LRU Buffer Replacement Strategy for data pages.
  END OF QUERY PLAN FOR SUBQUERY 1.
Total estimated I/O cost for statement 11 (at line 77): 378.
Parse and Compile Time 0.

План при выполнении только одного этого запроса (также без хинта с индеком).
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
QUERY PLAN FOR STATEMENT 1 (at line 1).
    STEP 1
        The type of query is SELECT.
Total estimated I/O cost for statement 1 (at line 1): 0.
Parse and Compile Time 0.
SQL Server cpu time: 0 ms.
QUERY PLAN FOR STATEMENT 1 (at line 1).
    STEP 1
        The type of query is UPDATE.
        The update mode is deferred.
        FROM TABLE
            #Card
        Nested iteration.
        Table Scan.
        Forward scan.
        Positioning at start of table.
        Run subquery 1 (at nesting level 1).
        Using I/O Size 64 Kbytes for data pages.
        With LRU Buffer Replacement Strategy for data pages.
        TO TABLE
            #Card
        Using I/O Size 8 Kbytes for data pages.
    STEP 1
NESTING LEVEL 1 SUBQUERIES FOR STATEMENT 1.
  QUERY PLAN FOR SUBQUERY 1 (at nesting level 1 and at line 4).
    Correlated Subquery.
    Subquery under an EXISTS predicate.
    STEP 1
        The type of query is SELECT.
        Evaluate Ungrouped ANY AGGREGATE.
        FROM TABLE
            #Card
            c1
        EXISTS TABLE : nested iteration.
        Index : i2
        Forward scan.
        Positioning by key.
        Keys are:
            ResourceID  ASC
        Using I/O Size 64 Kbytes for index leaf pages.
        With LRU Buffer Replacement Strategy for index leaf pages.
        Using I/O Size 64 Kbytes for data pages.
        With LRU Buffer Replacement Strategy for data pages.
  END OF QUERY PLAN FOR SUBQUERY 1.
И в первом и во втором случае данные в таблице одинаковые.
...
Рейтинг: 0 / 0
02.06.2011, 21:09
    #37292359
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
On 02.06.2011 20:41, LelikB wrote:
> Вопрос больше теоретический.

Теоретически такого быть не должно.

> Есть некий пакет в котором во временную таблицу с индексами вставляются данные
> (около 90000 строк), затем идет серия апдейтов этих данных.
> insert #Temp...

После пачки insert-ов очень хорошо было бы сделать UPDATE STATISTICS.
Или, ещё лучше, СНАЧАЛА вставлять данные,
а ПОТОМ делать

Код: plaintext
1.
2.
create clustered index i1 on #Card(CardID)
create index i2 on #Card(ResourceID, CardRole)

(UPDATE STATISTICS при этом уже не нужно )

Да, надеюсь, что create table и create index-ы у вас В ОТДЕЛЬНОМ
БАТЧЕ ?

> Так вот, обнаружилась интересная вещь: если выполнять каждый запрос
> последовательно, то оптимизатор корректно обнаруживает нужный индекс, все
> работает быстро. А если выполнить все в одном пакете, то на одном из запросов
> идет table scan.Ведь данные и в первом и во втором случае в таблице одни
> и те же.

Да, и кстати, если вы не делаете так, как я выше написал,
то оптимизатор при этом ничего о данных не знает.

Код: plaintext
1.
2.
3.
4.
5.
6.
  update #Card
  set  isMain =  1 
  where  isActive=  0 
     and  not  exists  (select  1  from #Card c1 (index  i2)
                    where #Card.ResourceID = c1.ResourceID
                      and isActive =  1  )

Странно, что не решают сканиться ВСЕ запросы на UPDATE,
поскольку для оптимизатора таблица ваша пуста.
Других данных у него нет, и он считает, что она пуста.
Или немного заполнена.
Скорее всего, случайно оптимизатор решает сканить именно
на этом запросе. А ещё вернее всего, для остальных
запросов table scan -- реально самая оптимальная стратегия,
и вы просто не заметили, что там тоже table scan-ы.




Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
02.06.2011, 21:12
    #37292365
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
On 02.06.2011 20:52, LelikB wrote:

> И в первом и во втором случае данные в таблице одинаковые.

Рассказывайте подробнее какими батчами всё это выполнялось
в двух случаях, а особенно как create table и index.

Да, кстати, "чисто теоретически" в таком случае вовсе не
зазорно поставить хинты.

Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
03.06.2011, 13:39
    #37293421
LelikB
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
MasterZivДа, надеюсь, что create table и create index-ы у вас В ОТДЕЛЬНОМ
БАТЧЕ ?

Нет, все запросы в одном пакете.
В общем-то в этом и была проблема, просто я не понимал почему для оптимизатора это может быть важно.
MasterZivДа, и кстати, если вы не делаете так, как я выше написал,
то оптимизатор при этом ничего о данных не знает.

MasterZivдля оптимизатора таблица ваша пуста.
Других данных у него нет, и он считает, что она пуста.

Спасибо за развернутый ответ теперь все предельно понятно.
...
Рейтинг: 0 / 0
03.06.2011, 13:45
    #37293438
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
On 03.06.2011 14:39, LelikB wrote:

> Да, надеюсь, что create table и create index-ы у вас В ОТДЕЛЬНОМ
> БАТЧЕ ?
>
>
> Нет, все запросы в одном пакете.

И CREATE TABLE ?
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
03.06.2011, 14:39
    #37293562
LelikB
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
MasterZiv,
В данном конкретном случае create table и create index в одном пакете, а insert и серия update - в другом. Т.е. всего два пакета.
Но я никогда не задумывался над необходимостью их разделения на разные пакеты, в данном случае я сделал это только для удобства. Не подскажете, почему это может быть необходимо?
...
Рейтинг: 0 / 0
03.06.2011, 14:54
    #37293604
cherrex_Den
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
LelikBMasterZiv,
В данном конкретном случае create table и create index в одном пакете, а insert и серия update - в другом. Т.е. всего два пакета.
Но я никогда не задумывался над необходимостью их разделения на разные пакеты, в данном случае я сделал это только для удобства. Не подскажете, почему это может быть необходимо?

Так как индекс создан до вставки, при вставке(insert), ASE нужно заполнить не только таблицу , но и индекс! плюс оптимизатор нечего не знает о статистике по этой таблице и по индексам.

Нужно так:

1-батч:
а. создал таблицу
б. залил(insert) данные
2-батч
а. сделал индекс
б. сделал апдэйт

И индекс создадите быстрей и статистика на апдэйтах будет актуальной!!!
...
Рейтинг: 0 / 0
03.06.2011, 15:35
    #37293691
LelikB
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
cherrex_Den
Так как индекс создан до вставки, при вставке(insert), ASE нужно заполнить не только таблицу , но и индекс!

А в случае кластерного индекса? Его-то наверняка имеет смысл создать до вставки?
cherrex_Den2-батч
а. сделал индекс
б. сделал апдэйт

Но тогда оптимизатор не будет знать об индексе при апдейтах, т.е. а. и б. также имеет смысл разделить?
...
Рейтинг: 0 / 0
03.06.2011, 16:06
    #37293776
cherrex_Den
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
LelikB,

LelikBА в случае кластерного индекса? Его-то наверняка имеет смысл создать до вставки?

нет. оптимизатор строит план основываясь на статистику! он тупо может даже не знать сколько строк в таблице, если нет статистики по таблице.

LelikBНо тогда оптимизатор не будет знать об индексе при апдейтах, т.е. а. и б. также имеет смысл разделить?

Почему? Создания индекса еще как раз и обновляет статистику!
...
Рейтинг: 0 / 0
03.06.2011, 16:10
    #37293788
komrad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
LelikBMasterZivдля оптимизатора таблица ваша пуста.
Других данных у него нет, и он считает, что она пуста.

Спасибо за развернутый ответ теперь все предельно понятно.

не считает он её пустой
но и реальной картины у него нет

насколько я помню из документации, оптимизатор предполагает некоторое кол-во записей ... в районе сотни, если не изменяет память
...
Рейтинг: 0 / 0
03.06.2011, 16:28
    #37293842
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
On 03.06.2011 16:35, LelikB wrote:

> А в случае кластерного индекса? Его-то наверняка имеет смысл создать до вставки?
> cherrex_Den

Нет. После.

> Но тогда оптимизатор не будет знать об индексе при апдейтах, т.е. *а.* и *б.*
> также имеет смысл разделить?

Да.

Я что понять-то не могу, так это как вы умудряетесь в один батч запихать
create table, create index и всё остальное, когда вроде бы как все DDL
дожны быть ТОЛЬКО ОТДЕЛЬНЫМ БАТЧЕМ (если не в процедуре или триггере).
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
03.06.2011, 16:29
    #37293844
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
On 03.06.2011 16:35, LelikB wrote:
> А в случае кластерного индекса? Его-то наверняка имеет смысл создать до вставки?

Вообще, не делали бы вы на временные таблицы-то кластерные индексы. Нафиг они
там ?
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
03.06.2011, 16:31
    #37293849
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
On 03.06.2011 17:10, komrad wrote:

> не считает он её пустой
> но и реальной картины у него нет

Ну я как бы загрубил, конечно, он ничего не считает,
он просто использует статистику для таблицы по умолчанию,
там (в разных версиях может быть по-разному) что-то типа
10 страниц, т.е. почти пустая таблица.

Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
03.06.2011, 16:37
    #37293870
komrad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
...
Рейтинг: 0 / 0
03.06.2011, 16:41
    #37293875
komrad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
MasterZivOn 03.06.2011 17:10, komrad wrote:

> не считает он её пустой
> но и реальной картины у него нет

Ну я как бы загрубил, конечно, он ничего не считает,
он просто использует статистику для таблицы по умолчанию,
там (в разных версиях может быть по-разному) что-то типа
10 страниц, т.е. почти пустая таблица.



нашел таки в документации ;)

цитатаThe optimizer assumes that any such table has 10 data pages and 100 rows. If the table is really large, this assumption can lead the optimizer to choose a suboptimal query plan.
...
Рейтинг: 0 / 0
03.06.2011, 17:08
    #37293944
LelikB
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
MasterZiv
Вообще, не делали бы вы на временные таблицы-то кластерные индексы. Нафиг они там ?

Не задумывался над этим.
Чтобы ссылка во втором ключе была сразу на CardID и в случае если надо узнать CardID по ResourceID, то не требовалось бы чтение таблицы, достаточно было чтения индекса.
Можно, конечно, для достижения того же результата сделать CardID первичным ключом:
Код: plaintext
1.
2.
3.
create table #Card 
(  CardID         numeric( 15 , 0 ) primary key
...
и сделать обычный индекс на CardID и ResourceID:
Код: plaintext
1.
2.
create index i1 on #Card(CardID)  
create index i2 on #Card(ResourceID, CardRole)  
В моем случае происходит только одна вставка в таблицу, дополнительных данных в середину таблицы (по CardID) не предвидится.
В чем будет недостаток временной таблицы в случае кластерного индекса?


MasterZiv
как вы умудряетесь в один батч запихать
create table, create index и всё остальное, когда вроде бы как все DDL
дожны быть ТОЛЬКО ОТДЕЛЬНЫМ БАТЧЕМ (если не в процедуре или триггере).

Код: plaintext
1.
2.
3.
4.
5.
create table #t (t int)
insert #t select  1 
insert #t select  2 
select * from #t
drop table #t
Никаких проблем. Особенности связки Diasoft FA# --- BDE --- Sybase ASE?

komrad , благодарю за ссылки.
...
Рейтинг: 0 / 0
03.06.2011, 17:32
    #37294000
LelikB
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
[quot LelikB]MasterZiv
Можно, конечно, для достижения того же результата сделать CardID первичным ключом:
и сделать обычный индекс на CardID

Написал не подумав, что для первичного ключа и так кластерный индекс будет создан.
...
Рейтинг: 0 / 0
03.06.2011, 18:01
    #37294057
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
On 03.06.2011 18:08, LelikB wrote:

> Чтобы ссылка во втором ключе была сразу на CardID и в случае если надо узнать
> CardID по ResourceID, то не требовалось бы чтение таблицы, достаточно было
> чтения индекса.

В этом что ли ?

create clustered index i1 on #Card(CardID)
create index i2 on #Card(ResourceID, CardRole)

Это, извини, ты попутал. Это тебе не MSSQLServer, это ASE.

В листах некластерных индексов ROWID лежит, а не значения ключей
кластерного индекса.

> Можно, конечно, для достижения того же результата сделать CardID первичным ключом:
>
> create table #Card
> ( CardID numeric(*15*,*0*)primary key
> ..
>
> и сделать обычный индекс на CardID и ResourceID:
>
> create index i1on #Card(CardID)

Зачем тебе ДВА индекса по CardID ?

> create index i2on #Card(ResourceID, CardRole)
>
> В моем случае происходит только одна вставка в таблицу, дополнительных данных в
> середину таблицы (по CardID) не предвидится.


> В чем будет недостаток временной таблицы в случае кластерного индекса?

Да особенно ни в чём, просто на фиг он не нужен. Создание кластерного
вызовет больше IO, потому что данные таблицы надо копировать, и ещё
пересоздаст все некластерные индексы, если они есть.

> Никаких проблем. Особенности связки Diasoft FA# --- BDE --- Sybase ASE?

Не знаю ... странно очень.
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
03.06.2011, 18:37
    #37294110
LelikB
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
План запроса в пакете и без
MasterZiv,

Код: plaintext
1.
2.
Это, извини, ты попутал. Это тебе не MSSQLServer, это ASE.
В листах некластерных индексов ROWID лежит, а не значения ключей
кластерного индекса.
Действительно, здесь я ошибался. Посмотрел планы запросов и убедился в этом.

Спасибо за ответы!
...
Рейтинг: 0 / 0
Форумы / Sybase ASA, ASE, IQ [игнор отключен] [закрыт для гостей] / План запроса в пакете и без / 20 сообщений из 20, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]