Переключение на Главную Страницу Страницы: 1 ОтправитьПечать
Горячая тема (более 10 ответов) Помогите оптимизировать запрос (число прочтений - 3344 )
al_zzz
Senior Member
****
Отсутствует


1C++ ->

Сообщений: 361
Местоположение: Барнаул
Зарегистрирован: 05. Сентября 2009
Пол: Мужской
Помогите оптимизировать запрос
18. Марта 2011 :: 05:25
Печать  
Задача заключается в следующем: необходимо получить факты продаж(количество документов продаж) за период:
Код
Выбрать все
Текстзапроса = "-- qryMaker:Ост по дням.2010.05.18.17.29.05
		|SELECT Ном.ID [Номенклатура $Справочник.Номенклатура]
		|   , Sum(ПродВыборка.Прод) Продажа
		|   , Sum(ТаблицаФактов.Факт) ФП
		|FROM $Справочник.Номенклатура AS Ном With (NOLOCK)
		|    Left OUTER JOIN
		|	(SELECT ПродажиОбороты.Номенклатура Номенк
		|	 , SUM(ПродажиОбороты.КоличествоОборот - ПродажиОбороты.КоличествоВОборот) Прод
		|	 FROM $РегистрОбороты.Продажи(:НачДата,
		|	 :КонДата~,
		|	 ,
		|	 RIGHT OUTER JOIN $Справочник.Номенклатура AS Ном With (NOLOCK) ON Ном.ID = Номенклатура
		|	  ,
		|	 (Номенклатура in (Select val from #СписокНоменклатуры))
		|	 AND (Склад = :ВыбСклад)
		|	   ,
		|	  Номенклатура,) AS ПродажиОбороты
		|	 GROUP BY ПродажиОбороты.Номенклатура) As ПродВыборка
		|			   On (ПродВыборка.Номенк = Ном.Id) -- And (Dat1.Dat=ПродВыборка.Период)
		|     Left Outer Join (Select ТаблицаФактов_СВ.Номенклатура Номенклатура
		|		    ,	Sum(ТаблицаФактов_СВ.Факт) Факт
		|		   From
		|		   (SELECT
		|		   $Продажи.Номенклатура Номенклатура
		|		   , Журнал.IDDOC [Док $Документ]
		|		   , Журнал.IDDOCDEF Док_вид
		|		   , Факт = Case Журнал.IDDOCDEF
		|		   When $ВидДокумента.ВозвратОтПокупателя Then -1
		|								  Else 1 End
		|		   FROM $Регистр.Продажи AS Продажи With (NOLOCK)
		|		   INNER JOIN _1SJOURN AS Журнал With (NOLOCK) ON Продажи.IDDOC = Журнал.IDDOC
		|		   WHERE (Журнал.DATE_TIME_IDDOC >= :НачДата)
		|		   AND (Журнал.DATE_TIME_IDDOC <= :КонДата~)
		|		   And ($Продажи.Склад = :ВыбСклад)
		|		   And ($Продажи.Номенклатура in (Select val From #СписокНоменклатуры))
		|		   GROUP BY $Продажи.Номенклатура
		|	 		       , Журнал.IDDOC
		|			    , Журнал.IDDOCDEF
		|		    ) As ТаблицаФактов_СВ
		|		    Group By  ТаблицаФактов_СВ.Номенклатура
		|		    ) As ТаблицаФактов On Ном.Id = ТаблицаФактов.Номенклатура
		|WHERE	(Ном.Id in (Select val from #СписокНоменклатуры))
		|GROUP BY Ном.ID, Ном.Descr
		|Order By Ном.Descr
		|"; 


Как его можно оптимизировать?
  

Каждая система проходит три стадии:&&1) Шумиха&&2) Неразбериха&&3) Поиск виновных (собственно, рабочий процесс)&&4) Наказание невиновных&&5) Награждение непричастных&& В.М. Глушков
Наверх
 
IP записан
 
Eprst
God Member
*****
Отсутствует



Сообщений: 3397
Зарегистрирован: 08. Октября 2007
Re: Помогите оптимизировать запрос
Ответ #1 - 18. Марта 2011 :: 06:18
Печать  
А чего, нужно весь справочник в итоге видеть ?
ЗЫ: да, еще зачетно делать right join унутри ВТ + а потом фильтровать по списку номенклатуры..
  
Наверх
 
IP записан
 
Satans Claws
God Member
*****
Отсутствует


1C++ rocks!

Сообщений: 721
Зарегистрирован: 29. Ноября 2010
Re: Помогите оптимизировать запрос
Ответ #2 - 18. Марта 2011 :: 07:16
Печать  
1) зачем в ВТ ПродажиОбороты делается Right Join спр.Номенклатура? Оптимизатор, скорее всего, увидит, что с этого джойна не используются поля и обрубит его, но зачем лишний раз выносить ему моск?

2) ты делаешь выборку по номенклатуре, джойнишь к ней обороты и потом делаешь групбай.
А если по какой-то номенклатуре движений не было? значит под sum() попадет NULL.
С фактами аналогично.

3) Ну и самый верхний Групбай не нужен - в спр.Номенклатура ID уникален, а джойны уже сгруппированы по номенклатуре.
  
Наверх
 
IP записан
 
Satans Claws
God Member
*****
Отсутствует


1C++ rocks!

Сообщений: 721
Зарегистрирован: 29. Ноября 2010
Re: Помогите оптимизировать запрос
Ответ #3 - 18. Марта 2011 :: 07:17
Печать  
Eprst писал(а) 18. Марта 2011 :: 06:18:
А чего, нужно весь справочник в итоге видеть ?


Там же в конце условие (Ном.Id in (Select val from #СписокНоменклатуры)) есть



PS кстати, на счет Right Join-а - далеко не факт, что оптимизатор его отсечет. Левые джойны он отсекает успешно, а вот правый - может и строк добавлять. Так что не факт...
  
Наверх
 
IP записан
 
Eprst
God Member
*****
Отсутствует



Сообщений: 3397
Зарегистрирован: 08. Октября 2007
Re: Помогите оптимизировать запрос
Ответ #4 - 18. Марта 2011 :: 07:20
Печать  
Satans Claws писал(а) 18. Марта 2011 :: 07:17:
Eprst писал(а) 18. Марта 2011 :: 06:18:
А чего, нужно весь справочник в итоге видеть ?


Там же в конце условие (Ном.Id in (Select val from #СписокНоменклатуры)) есть


это я уже не смотрел..
и так видно, что хрень какую то запрашивает изначально Улыбка
Зачем вообще запрос там по справочнику нужен - не ясно..
это вообще лишнее.
  
Наверх
 
IP записан
 
al_zzz
Senior Member
****
Отсутствует


1C++ ->

Сообщений: 361
Местоположение: Барнаул
Зарегистрирован: 05. Сентября 2009
Пол: Мужской
Re: Помогите оптимизировать запрос
Ответ #5 - 04. Апреля 2011 :: 10:11
Печать  
Всё вышеперечисленное принял к сведению и, по возможности, исправил. Теперь такая проблема: обработка с несколькими запросами(в том числе и с данным) "вешает 1с-ку". Точнее, захватывает таблицы и делает другим пользователям слайдшоу.
Стало заметно, когда обработка стала интенсивно использоваться.
Тексты запроса перечислены в функции "ТекстЗапроса(Парам)".
Заранее благодарен за помощь.
  

___________005.ert ( 89 KB | Загрузки )

Каждая система проходит три стадии:&&1) Шумиха&&2) Неразбериха&&3) Поиск виновных (собственно, рабочий процесс)&&4) Наказание невиновных&&5) Награждение непричастных&& В.М. Глушков
Наверх
 
IP записан
 
Z1
God Member
*****
Отсутствует


I Love YaBB 2!

Сообщений: 2906
Местоположение: Москва
Зарегистрирован: 26. Мая 2006
Пол: Мужской
Re: Помогите оптимизировать запрос
Ответ #6 - 04. Апреля 2011 :: 10:52
Печать  
al_zzz писал(а) 04. Апреля 2011 :: 10:11:
Всё вышеперечисленное принял к сведению и, по возможности, исправил. Теперь такая проблема: обработка с несколькими запросами(в том числе и с данным) "вешает 1с-ку". Точнее, захватывает таблицы и делает другим пользователям слайдшоу.
Стало заметно, когда обработка стала интенсивно использоваться.
Тексты запроса перечислены в функции "ТекстЗапроса(Парам)".
Заранее благодарен за помощь.

Елси речь идет гле пар = 1 то гораздо лучше вместо


           Текстзапроса = "-- qryMaker:Ост по дням.2010.05.18.17.29.05
           |SELECT Ном.Val [Номенклатура $Справочник.Номенклатура]
           |      , Dat1.Dat День
           |   , IsNull(Sum(Выборка.КонОст),0) Остаток
           |   , case  when Sum(Выборка.КонОст) is null
           |          then 0
           |          else 1 end Провалы
           |FROM #СписокНоменклатуры AS Ном With (NOLOCK)
           |   Full Outer Join Dat_  As Dat1
           |                         On  1=1  
           |      Left OUTER JOIN


написать  как-то так ( все равно ты же ограничиваешь номенклатуру папкой и поэтому первый select на мой взгляд не нужен.
Код
Выбрать все
		Текстзапроса = "-- qryMaker:Ост по
|SELECT Ном.Val [Номенклатура $Справочник.Номенклатура]
		|	, Dat1.Dat День
		|   , IsNull(Sum(Выборка.КонОст),0) Остаток
		|   , case  when Sum(Выборка.КонОст) is null
		|	    then 0
		|	    else 1 end Провалы
		|FROM  Dat_  As Dat1 WITH(NOLOCK)

		|	Left OUTER JOIN
 



и обязательно  в таблице Dat_ по полю Dat должен быть индекс
« Последняя редакция: 04. Апреля 2011 :: 12:18 - Z1 »  
Наверх
 
IP записан
 
Eprst
God Member
*****
Отсутствует



Сообщений: 3397
Зарегистрирован: 08. Октября 2007
Re: Помогите оптимизировать запрос
Ответ #7 - 04. Апреля 2011 :: 12:18
Печать  
Лишние group by в текстах запроса..
ЗЫ: 10 видов  документов Перемещение.. это тоже как-то не очень.
  
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Помогите оптимизировать запрос
Ответ #8 - 04. Апреля 2011 :: 13:15
Печать  
al_zzz

Попробуй. Но это не вникая в логику запросов. Там ещё есть куда оптимизировать.
  

___________005_001.ert ( 98 KB | Загрузки )

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
al_zzz
Senior Member
****
Отсутствует


1C++ ->

Сообщений: 361
Местоположение: Барнаул
Зарегистрирован: 05. Сентября 2009
Пол: Мужской
Re: Помогите оптимизировать запрос
Ответ #9 - 05. Апреля 2011 :: 03:13
Печать  
berezdetsky писал(а) 04. Апреля 2011 :: 13:15:
al_zzz

Попробуй. Но это не вникая в логику запросов. Там ещё есть куда оптимизировать.


Заменил тексты запросов в функции "ТекстЗапроса(Парам)" на тексты, которые взял из Вами отредактированной  обработки.
Проблема не исчезла - так же слайд-шоу у всех пользователей(это главная проблема).
Причина по большей части в первом запросе( при получении остатков).
Заметил, что даже после окончания обработки эфект слайд-шоу наблюдается некоторое время.
Может ли быть ситуация, когда запрос выполнился, но таблица осталась захваченной запросом?
В копии пытались запустить обработку с двух разных пользователей в различных вариантах - получить нужного эффекта воспроизвести не удалось.
Можно как-то сделать, чтоб пользователи не могли её одновременно запускать?
Может виртуальные таблицы как-то самому получать, чтоб не захватывать таблицы БД? Возможно ли это?
« Последняя редакция: 05. Апреля 2011 :: 04:45 - al_zzz »  

Каждая система проходит три стадии:&&1) Шумиха&&2) Неразбериха&&3) Поиск виновных (собственно, рабочий процесс)&&4) Наказание невиновных&&5) Награждение непричастных&& В.М. Глушков
Наверх
 
IP записан
 
al_zzz
Senior Member
****
Отсутствует


1C++ ->

Сообщений: 361
Местоположение: Барнаул
Зарегистрирован: 05. Сентября 2009
Пол: Мужской
Re: Помогите оптимизировать запрос
Ответ #10 - 05. Апреля 2011 :: 05:06
Печать  
al_zzz писал(а) 05. Апреля 2011 :: 03:13:
berezdetsky писал(а) 04. Апреля 2011 :: 13:15:
al_zzz

Попробуй. Но это не вникая в логику запросов. Там ещё есть куда оптимизировать.


Заменил тексты запросов в функции "ТекстЗапроса(Парам)" на тексты, которые взял из Вами отредактированной  обработки.
Проблема не исчезла - так же слайд-шоу у всех пользователей(это главная проблема).
Причина по большей части в первом запросе( при получении остатков).
Заметил, что даже после окончания обработки эфект слайд-шоу наблюдается некоторое время.
Может ли быть ситуация, когда запрос выполнился, но таблица осталась захваченной запросом?
В копии пытались запустить обработку с двух разных пользователей в различных вариантах - получить нужного эффекта воспроизвести не удалось.
Можно как-то сделать, чтоб пользователи не могли её одновременно запускать?
Может виртуальные таблицы как-то самому получать, чтоб не захватывать таблицы БД? Возможно ли это?

В копии удалось воспроизвести ситуацию, когда выполнил обработку по второму варианту(1 вариант - подтоварка складов по Поступлению ТМЦ, 2-ой вариант - подтоварка складов по всем остаткам оптового склада).
Там последовательно подтоваривались четыре склада. На 4-ом обработка зависла(к сожалению, не удалось выяснить на каком запросе) и загрузила процессор на 95%.
Можно ли как-то ограничить ресурсы для сеанса 1c MS Sql Server 2000?
Буду локализовать причину дальше и жду Ваших советов.
  

Каждая система проходит три стадии:&&1) Шумиха&&2) Неразбериха&&3) Поиск виновных (собственно, рабочий процесс)&&4) Наказание невиновных&&5) Награждение непричастных&& В.М. Глушков
Наверх
 
IP записан
 
berezdetsky
1c++ power user
Отсутствует


barba non facit sisadminum

Сообщений: 1986
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Помогите оптимизировать запрос
Ответ #11 - 05. Апреля 2011 :: 07:03
Печать  
al_zzz писал(а) 05. Апреля 2011 :: 05:06:
В копии удалось воспроизвести ситуацию, когда выполнил обработку по второму варианту

Это можно улучшить, если включить отбор движений по измерению Номенклатура регистра Продажи и переписать запрос как
Код
Выбрать все
Текстзапроса = "
|SELECT Ном.Val [Номенклатура $Справочник.Номенклатура]
|   , Sum(ПродВыборка.КоличествоОборот - ПродВыборка.КоличествоВОборот) Продажа
|   , Sum(ТаблицаФактов.Факт) ФП
|FROM #СписокНоменклатуры AS Ном With (NOLOCK)
|    Left OUTER JOIN
|	$РегистрОбороты.Продажи(:НачДата, :КонДата~,,,
|	 (Номенклатура in (Select val from #СписокНоменклатуры))
|	 AND (Склад = :ВыбСклад),
|	  Номенклатура,) As ПродВыборка On (ПродВыборка.Номенклатура = Ном.Val)
|     Left Outer Join (SELECT $Продажи.Номенклатура Номенклатура
|		   , Факт = Sum(Case When Продажи.IDDOCDEF = $ВидДокумента.ВозвратОтПокупателя Then -1 Else 1 End)
|		   FROM $Регистр.Продажи AS Продажи With (NOLOCK)
|		   WHERE (Продажи.DATE_TIME_IDDOC >= :НачДата)
|		   AND (Продажи.DATE_TIME_IDDOC <= :КонДата~)
|		   And ($Продажи.Склад = :ВыбСклад)
|		   And ($Продажи.Номенклатура in (Select val From #СписокНоменклатуры))
|		    Group By  $Продажи.Номенклатура
|		    ) As ТаблицаФактов On Ном.Val = ТаблицаФактов.Номенклатура  
|GROUP BY Ном.Val
|"; 


А если left outer здесь не принципиален, можно ещё немного ускорить.

Памяти SQL серверу хватает?
  

пароль как коньяк, чем больше звездочек, тем лучше
Наверх
IP записан
 
al_zzz
Senior Member
****
Отсутствует


1C++ ->

Сообщений: 361
Местоположение: Барнаул
Зарегистрирован: 05. Сентября 2009
Пол: Мужской
Re: Помогите оптимизировать запрос
Ответ #12 - 06. Апреля 2011 :: 03:10
Печать  
Оптимизировал самый первый запрос - там мне надо было получить дни в наличии на складе и конечный остаток. В итоге:
Код
Выбрать все
ТекстЗапроса = "
		|Select
		|    Выборка.Номенклатура [Номенклатура $Справочник.Номенклатура]
		| ,  (Case When (IsNull(Выборка.ДнейНаСкладе,0) = 0) And (IsNull(Sum(ОстаткиТМЦОстатки.КоличествоОстаток),0) <> 0) Then
		|     DATEDIFF(day, :НачДата, :КонДата) + 1
		|    Else
		|	IsNull(Выборка.ДнейНаСкладе,0)
		|    End) As Дней
		|,   Sum(ОстаткиТМЦОстатки.КоличествоОстаток) Остаток
		|From  
		|   (SELECT
		|   ВлЗапрос.Номенклатура Номенклатура
		|   , SUM(
		|   CASE WHEN ВлЗапрос.КоличествоНачОст>0 THEN  
		|	CASE WHEN ВлЗапрос.Период=convert(datetime,:НачДата,112) THEN
		|					     CASE WHEN ВлЗапрос.КоличествоКонОст<=0 THEN  
		|		1
		|	   ELSE
		|		DATEDIFF(day, ВлЗапрос.Период,convert(datetime,:КонДата,112)) + 1
		|	   END
		|	ELSE
		|			   CASE WHEN ВлЗапрос.КоличествоКонОст<=0 THEN
		|		-DATEDIFF(day, ВлЗапрос.Период,convert(datetime,:КонДата,112))
		|	   END
		|	END		    
		|   ELSE
		|	CASE WHEN ВлЗапрос.КоличествоКонОст>0 THEN
		|	   DATEDIFF(day, ВлЗапрос.Период,convert(datetime,:КонДата,112)) + 1
		|	END
		|   END) as ДнейНаСкладе
		|FROM(
		|   SELECT ОстаткиТМЦОстаткиОбороты.Номенклатура
		|	, ОстаткиТМЦОстаткиОбороты.Период as Период
		|	, ОстаткиТМЦОстаткиОбороты.КоличествоКонечныйОстаток КоличествоКонОст
		|	, ОстаткиТМЦОстаткиОбороты.КоличествоНачальныйОстаток КоличествоНачОст
		|   FROM да,
		|		   ,
		|	    --   (Номенклатура = :ВыбНоменклатура)
		|		    (Номенклатура in (select val from #СписокНоменклатуры))
		|		  And (Склад = :ВыбСклад)
		|		   ,(Номенклатура),) AS ОстаткиТМЦОстаткиОбороты
		|   ) AS ВлЗапрос	    
		|   GROUP BY ВлЗапрос.Номенклатура
		|-- ORDER BY ВлЗапрос.Номенклатура
		|   ) As Выборка
		|  Inner Join $РегистрОстатки.ОстаткиТМЦ(:КонДата~,,
		|		(Номенклатура in (select val from #СписокНоменклатуры)) And (Склад = :ВыбСклад),
		|		(Номенклатура),) AS ОстаткиТМЦОстатки On ОстаткиТМЦОстатки.Номенклатура = Выборка.Номенклатура
		|Group By Выборка.Номенклатура, Выборка.ДнейНаСкладе
		|"; 

.
Без обработки таблицы на клиенте скорость возросла с 2-3 минут по 6 000 позиций до 20 секунд.
Было решено отказаться от учета фактов продаж в итоге запрос по продажам стал выглядеть:
Код
Выбрать все
Текстзапроса = "-- qryMaker:Ост по дням.2010.05.18.17.29.05
		|SELECT Продажи.Номенклатура [Номенклатура $Справочник.Номенклатура]
		|   , Sum(Продажи.КоличествоОборот - Продажи.КоличествоВОборот) Продажа
		|FROM $РегистрОбороты.Продажи(:НачДата, :КонДата~,,,
		|	 (Номенклатура in (Select val from #СписокНоменклатуры))
		|	 AND (Склад = :ВыбСклад),
		|	  Номенклатура,) As Продажи  
		|GROUP BY Продажи.Номенклатура
		|"; 


Не помогло - так же занимаются все ресурсы сервера. Копаю дальше...
  

Каждая система проходит три стадии:&&1) Шумиха&&2) Неразбериха&&3) Поиск виновных (собственно, рабочий процесс)&&4) Наказание невиновных&&5) Награждение непричастных&& В.М. Глушков
Наверх
 
IP записан
 
al_zzz
Senior Member
****
Отсутствует


1C++ ->

Сообщений: 361
Местоположение: Барнаул
Зарегистрирован: 05. Сентября 2009
Пол: Мужской
Re: Помогите оптимизировать запрос
Ответ #13 - 06. Апреля 2011 :: 03:10
Печать  
Может быть, всё дело в следующем блоке?
Код
Выбрать все
ИТСтат.ЛевоеСоединение("Номенклатура",ИТДин,"Номенклатура", "Продажа_б");
	ИТСтат.ЛевоеСоединение("Номенклатура",ИТДин1,"Номенклатура", "Продажа_м");
	ИТСтат.ЛевоеСоединение("Номенклатура",ИтМП,"Номенклатура", "МП");
	ИТСтат.ВнутреннееСоединение("Номенклатура",ИТОстатков,"Номенклатура", "Дней_б");
	ИТСтат.ВнутреннееСоединение("Номенклатура",ИТОстатков1,"Номенклатура", "Остаток, Дней_м"); 

?
  

Каждая система проходит три стадии:&&1) Шумиха&&2) Неразбериха&&3) Поиск виновных (собственно, рабочий процесс)&&4) Наказание невиновных&&5) Награждение непричастных&& В.М. Глушков
Наверх
 
IP записан
 
Переключение на Главную Страницу Страницы: 1
ОтправитьПечать