различная оптимизация одного и того же запроса

Михаил Иоссель
Дата: 16.09.2006 20:49:08
Написал обычный запрос
 
select
  d.accMainnumber as dbt , d.acc_id_val as acc_id, d.acc_own_val as acc_own,cr_value, k.accmainnumber as krdt , d.client_id
 into #prov
from farcarr1 inner join  #account_dbt d on d.acc_own_val = cr_owner and d.acc_id_val = cr_debet
              inner join #account_krd k on k.acc_own_val = cr_owner and k.acc_id_val = cr_credit
where 
     cr_moment >= @p_from
and   cr_moment <= @p_to

С оЧень большой таблицей farcarr1 (миллионы записей) , решив значительно сократить время работы запроса за счет того что заранее отобрал данные в таблицы
#account_dbt и #account_krd , а потом выгрузить найденное в небольшую временную табличку . Соответсвующие поля в farcarr1 (cr_debet и cr_credit) - Интеджеры и имеют кластерные индексы

Проблема :
ЗАпускаю код просто в QA - Работает секунд 30, сгенерил хранимую процедуру - 15 минут. У меня на серваке 4 отдельных процессора.

Посмотрел планы выполнения :
Для QA:


Execution Tree
--------------
Table Insert(OBJECT:([#prov]), SET:([#prov].[client_id]=[d].[client_id], [#prov].[krdt]=[k].[AccMainNumber], [#prov].[cr_value]=[farcarr1].[cr_value], [#prov].[acc_own]=[d].[acc_own_val], [#prov].[acc_id]=[d].[acc_id_val], [#prov].[dbt]=[d].[AccMainNumber]))
  |--Top(ROWCOUNT est 0)
       |--Parallelism(Gather Streams)
            |--Hash Match(Inner Join, HASH:([k].[acc_own_val], [k].[acc_id_val])=([d].[acc_own_val], [farcarr1].[cr_credit]), RESIDUAL:([d].[acc_own_val]=[k].[acc_own_val] AND [k].[acc_id_val]=[farcarr1].[cr_credit]))
                 |--Parallelism(Repartition Streams, PARTITION COLUMNS:([k].[acc_own_val], [k].[acc_id_val]))
                 |    |--Table Scan(OBJECT:([tempdb].[dbo].[#account_krd________________________________________________________________________________________________________000000001912] AS [k]))
                 |--Parallelism(Repartition Streams, PARTITION COLUMNS:([d].[acc_own_val], [farcarr1].[cr_credit]))
                      |--Hash Match(Inner Join, HASH:([d].[acc_own_val], [d].[acc_id_val])=([farcarr1].[cr_owner], [farcarr1].[cr_debet]), RESIDUAL:([farcarr1].[cr_owner]=[d].[acc_own_val] AND [farcarr1].[cr_debet]=[d].[acc_id_val]))
                           |--Bitmap(HASH:([d].[acc_own_val], [d].[acc_id_val]), DEFINE:([Bitmap1006]))
                           |    |--Parallelism(Repartition Streams, PARTITION COLUMNS:([d].[acc_own_val], [d].[acc_id_val]))
                           |         |--Table Scan(OBJECT:([tempdb].[dbo].[#account_dbt________________________________________________________________________________________________________000000001912] AS [d]))
                           |--Parallelism(Repartition Streams, PARTITION COLUMNS:([farcarr1].[cr_owner], [farcarr1].[cr_debet]), WHERE:(PROBE([Bitmap1006])=TRUE))
                                |--Clustered Index Scan(OBJECT:([contour].[dbo].[farcarr1].[farcarr1_pk]), WHERE:([farcarr1].[cr_moment]>=[@p_from] AND [farcarr1].[cr_moment]<=[@p_to]))

для Хранимой процедуры:
xecution Tree
--------------
Table Insert(OBJECT:([#prov]), SET:([#prov].[client_id]=[d].[client_id], [#prov].[krdt]=[k].[AccMainNumber], [#prov].[cr_value]=[farcarr1].[cr_value], [#prov].[acc_own]=[d].[acc_own_val], [#prov].[acc_id]=[d].[acc_id_val], [#prov].[dbt]=[d].[AccMainNumber]))
  |--Top(ROWCOUNT est 0)
       |--Hash Match(Inner Join, HASH:([k].[acc_own_val], [k].[acc_id_val])=([d].[acc_own_val], [farcarr1].[cr_credit]), RESIDUAL:([d].[acc_own_val]=[k].[acc_own_val] AND [k].[acc_id_val]=[farcarr1].[cr_credit]))
            |--Table Scan(OBJECT:([tempdb].[dbo].[#account_krd] AS [k]))
            |--Nested Loops(Inner Join, OUTER REFERENCES:([d].[acc_id_val], [d].[acc_own_val]) WITH PREFETCH)
                 |--Table Scan(OBJECT:([tempdb].[dbo].[#account_dbt] AS [d]))
                 |--Clustered Index Seek(OBJECT:([contour].[dbo].[farcarr1].[farcarr1_pk]), SEEK:([farcarr1].[cr_owner]=[d].[acc_own_val] AND ([farcarr1].[cr_moment], [farcarr1].[cr_debet]) >= ([@p_from], [d].[acc_id_val]) AND ([farcarr1].[cr_moment], [farcarr1].[cr_debet]) <= ([@p_to], [d].[acc_id_val])),  WHERE:([farcarr1].[cr_debet]=[d].[acc_id_val]) ORDERED FORWARD)

Прошу подсказать , на что обратить внимание. Как заставить оптимизатор работать одинаково .
Михаил Иоссель
Дата: 17.09.2006 14:08:27
Похоже понял в чем дело .
Пи компиляции процедуры сервак еще не знает , какие будут таблицы #Acc_DBT и #acc_KRD из-за этого вообще не оптимизирует запрос .

Счас попробую придумать , как это решить .

Скорее всего через
exec (@SQL)
Александр Волок (def1983)
Дата: 17.09.2006 14:40:53
Рекомендовано все временные таблицы создавать в начале хранимой процедуры и использовать
insert #table select ... 
вместо
select * into #table
Михаил Иоссель
Дата: 17.09.2006 15:07:08
Кстати выполнение через
exec()
не помогло.
Михаил Иоссель
Дата: 17.09.2006 15:08:36
Там убийственное количество столбцов .. поэтому я и попробовал схалявить через
select * into # 
Михаил Иоссель
Дата: 17.09.2006 15:11:58
Кроме того заметил что после работы
 Insert into # select
порядок строк отличается против

 select  into #
смешно........
Дата: 17.09.2006 16:45:18
Михаил Иоссель
Кроме того заметил что после работы
 Insert into # select
порядок строк отличается против

 select  into #

про ПОРЯДОК СТРОК повеселили
А чем смотрели?
Есть ведь КУЧА и статей, и тем в этом же форуме, где говорится, что к сиквел-серверу НЕЛЬЗЯ применять такого термина, как "порядок строк". Без использования команд ORDER BY "порядок" выводимых строк ПО ОПРЕДЕЛЕНИЮ будет СЛУЧАЙНЫЙ. Ну за исключением случаев, когда на таблице есть кластерный индекс...
ИТОГО: оценивайте планы запросов, времена выполнения и правильность данных - не заморачивайтесь на глупости....
Михаил Иоссель
Дата: 17.09.2006 18:21:00
Приколись , можно применить .

Задача -
тьма запросов для полочения первой попавшейся строки в случае сортировки по определенному полю

Select top1 a from b order by q

В таблице миллион записей , постоянно происходят удаления из таблицы

Если сортировать каждый раз - время выполнения запроса от чуть меньше 1 секунды до 2х секунд (16 гигов оперативки 4 камня )

Если сразу иметь правильно отсортированную таблицу
Select top1 a from b

Время выполнения запроса - запросов 500 в секунду .

Ниибаться оптимизация.
Михаил Иоссель
Дата: 17.09.2006 18:21:51
ТАк вот эта шняга работает :)
Anatoly Podgoretsky
Дата: 17.09.2006 18:36:38
Не в борделе