Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Помогите пожалуйста с запросом  (Прочитано 12629 раз)
0 Пользователей и 1 Гость смотрят эту тему.
SeAn1s
Интересующийся

ru
Offline Offline

« : 20-05-2010 03:26 » 

Существует справочник, где в качестве элементов документы.
В процедуре "ПриОткрытии" формы списка такого справочника производится удаление из справочника неправильных элементов.
Их поиск производится простым перебором, таким образом:
Код:
СписокНаУдаление = СоздатьОбъект("СписокЗначений");
Элемент = СоздатьОбъект("Справочник.ДокументыСклада");
ДокументыСклада = СоздатьОбъект("Справочник.ДокументыСклада");
ДокументыСклада.ВыбратьЭлементы(0); // выбирать элементы без учета иерархии
Пока ДокументыСклада.ПолучитьЭлемент() = 1 Цикл
Если ДокументыСклада.Документ.Вид() = "Перемещение" Тогда
Если (ДокументыСклада.Документ.Склад <> ДокументыСклада.Владелец) и (ДокументыСклада.Документ.СкладПолучатель <> ДокументыСклада.Владелец) Тогда
СписокНаУдаление.ДобавитьЗначение(ДокументыСклада.ТекущийЭлемент());
КонецЕсли;
ИначеЕсли ДокументыСклада.Документ.Склад <> ДокументыСклада.Владелец Тогда
СписокНаУдаление.ДобавитьЗначение(ДокументыСклада.ТекущийЭлемент());
КонецЕсли;
КонецЦикла;
Для а = 1 По СписокНаУдаление.РазмерСписка() Цикл
Если Элемент.НайтиЭлемент(СписокНаУдаление.ПолучитьЗначение(а)) = 1 Тогда
Попытка
Элемент.Удалить(1); // физическое удаление
Исключение
КонецПопытки;
КонецЕсли;
КонецЦикла;
Работает, но долго.
С целью оптимизации написал запрос, работает в 3 раза быстрее, но почему-то неправильно (в результаты попадает много лшних документов).
Помогите пожалуйста разобраться почему.
Вот то же с запросом:
Код:
Элемент = СоздатьОбъект("Справочник.ДокументыСклада");
ТекстЗапроса = "
//{{ЗАПРОС(Сформировать)
|Спр = Справочник.ДокументыСклада.ТекущийЭлемент;
|Владелец = Справочник.ДокументыСклада.Владелец;
|Док = Справочник.ДокументыСклада.Документ;
|Условие (((Док.Вид() = ""Перемещение"") И НЕ(Владелец в Док.Склад) И НЕ(Владелец в Док.СкладПолучатель)) ИЛИ (НЕ(Док.Вид() = ""Перемещение"") И НЕ(Владелец в Док.Склад)));
|Без Итогов;
|Группировка Спр Без Групп;
|";//}}ЗАПРОС

Запрос = СоздатьОбъект("Запрос");
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
Сообщить("Запрос не выполнен!");
Возврат;
КонецЕсли;
Пока Запрос.Группировка() = 1 Цикл
Если Элемент.НайтиЭлемент(Запрос.Спр) = 1 Тогда
Попытка
Элемент.Удалить(1); // физическое удаление
Исключение
КонецПопытки;
КонецЕсли;
КонецЦикла;
« Последнее редактирование: 20-05-2010 03:32 от SeAn1s » Записан
Kivals
Модератор

ca
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 20-05-2010 07:11 » 

Условие в запросе не соответствует условию в цикле. Перепиши его так же, как и в программе.
Не используй "в" - она работает медленней, чем сравнение равно/не равно
Учитывая что 7.7 выполняет запросы на клиенте можешь попробовать вынести условие в функцию (посмотри как отразится на скорости):
Код:
...
|Условие (ПроверитьСпр(Спр)=1);
...

Функция ПроверитьСпр(Спр)
Если Спр.Вид()="Перемещение" Тогда
Если (ДокументыСклада.Документ.Склад <> ДокументыСклада.Владелец) Тогда
Если (ДокументыСклада.Документ.СкладПолучатель <> ДокументыСклада.Владелец) Тогда
Возврат 1;
...
КонецЕсли;
Возврат 0;
КонецФункции

7.7 не умеет оптимизировать логические выражения, потому конструкции типа:
Код:
Если (Условие1) И (Условие2) ...
будет выполнятся дольше, чем
Код:
Если (Условие1) Тогда Если (Условие2) ...
В случае, когда Условие1=Ложь и одинаковое время в противном случае
Записан
SeAn1s
Интересующийся

ru
Offline Offline

« Ответ #2 : 21-05-2010 01:13 » 

Забыл сказать, что 1с7.7+sql2000 на win2k3 R2 SE x64
Захожу с клиентского компа.

Условие в запросе не соответствует условию в цикле. Перепиши его так же, как и в программе.

Спасибо, всё заработало!

Учитывая что 7.7 выполняет запросы на клиенте можешь попробовать вынести условие в функцию (посмотри как отразится на скорости):
Код:
...
|Условие (ПроверитьСпр(Спр)=1);
...

Функция ПроверитьСпр(Спр)
Если Спр.Вид()="Перемещение" Тогда
Если (ДокументыСклада.Документ.Склад <> ДокументыСклада.Владелец) Тогда
Если (ДокументыСклада.Документ.СкладПолучатель <> ДокументыСклада.Владелец) Тогда
Возврат 1;
...
КонецЕсли;
Возврат 0;
КонецФункции
С вынесенным в функцию условием чуть медленней, но в целом примерно так же.

В варианте проверки перебором также переделал условие (для удобства также вынес проверку в функцию), получилось так:
Код:
Функция ПроверитьДок(Док,Владелец)
Состояние("Инициализация интерфейса! Подождите окончания. Проверка документов склада за "+Док.ДатаДок);
Если Док.Вид()="Перемещение" Тогда
Если (Док.Склад <> Владелец) Тогда
Если (Док.СкладПолучатель <> Владелец) Тогда
Возврат 1;
КонецЕсли;
КонецЕсли;
ИначеЕсли Док.Склад <> Владелец Тогда
Возврат 1;
КонецЕсли;
Возврат 0;
КонецФункции // ПроверитьДок

...

СписокНаУдаление = СоздатьОбъект("СписокЗначений");
Элемент = СоздатьОбъект("Справочник.ДокументыСклада");
ДокументыСклада = СоздатьОбъект("Справочник.ДокументыСклада");
ДокументыСклада.ВыбратьЭлементы(0); // выбирать элементы без учета иерархии
Пока ДокументыСклада.ПолучитьЭлемент() = 1 Цикл
Если ПроверитьДок(ДокументыСклада.Документ,ДокументыСклада.Владелец) = 1 Тогда
СписокНаУдаление.ДобавитьЗначение(ДокументыСклада.ТекущийЭлемент());
КонецЕсли;
КонецЦикла;
Сообщить("На удаление:");
Для а = 1 По СписокНаУдаление.РазмерСписка() Цикл
Если Элемент.НайтиЭлемент(СписокНаУдаление.ПолучитьЗначение(а)) = 1 Тогда
Попытка
Сообщить(Элемент); // физическое удаление
Исключение
КонецПопытки;
КонецЕсли;
КонецЦикла;

работает 80-90 секунд

Вариант с запросом:
Код:
Функция ПроверитьДок(Док,Владелец)
Если Док.Вид()="Перемещение" Тогда
Если (Док.Склад <> Владелец) Тогда
Если (Док.СкладПолучатель <> Владелец) Тогда
Возврат 1;
КонецЕсли;
КонецЕсли;
ИначеЕсли Док.Склад <> Владелец Тогда
Возврат 1;
КонецЕсли;
КонецЕсли;
Возврат 0;
КонецФункции // ПроверитьДок

...

Элемент = СоздатьОбъект("Справочник.ДокументыСклада");
ТекстЗапроса = "
//{{ЗАПРОС(Сформировать)
|Спр = Справочник.ДокументыСклада.ТекущийЭлемент;
|Владелец = Справочник.ДокументыСклада.Владелец;
|Док = Справочник.ДокументыСклада.Документ;
|Условие (ПроверитьДок(Док,Владелец) = 1);
|Без Итогов;
|Группировка Спр Без Групп;
|";//}}ЗАПРОС

Запрос = СоздатьОбъект("Запрос");
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
Возврат;
КонецЕсли;
Пока Запрос.Группировка() = 1 Цикл
Если Элемент.НайтиЭлемент(Запрос.Спр) = 1 Тогда
Попытка
Сообщить(Элемент);
//Элемент.Удалить(1); // физическое удаление
Исключение
КонецПопытки;
КонецЕсли;
КонецЦикла;
Работает 110-150 (!) секунд.
Обычно запросом побыстрее, а тут вовсе даже наоборот, причём настолько! Жаль
Непонятно.
« Последнее редактирование: 21-05-2010 02:47 от SeAn1s » Записан
Kivals
Модератор

ca
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 21-05-2010 05:42 » 

Запросом быстрее только если его можно оптимизировать. А 7.7 к сожалению этого практически не умеет делать, т.е. возвращается весь список, а потом на клиенте перебирается и сравнивается с условием.
Если знаешь как - можешь промониторить какие данные SQL сервер возвращает в ответ на запрос. По идее будет полный список элементов...
Кстати - частый вызов Состояние() еще может притормаживать процесс
Записан
Ольга111
Интересующийся

ua
Offline Offline

« Ответ #4 : 29-05-2010 12:19 » 

Здравствуйте, подскажите, пожалуйста, что такое консоль запроса. У меня по заданию надо предоставить скриншот консоли запроса. Это т.е. результат работы запроса? Т.е. то, что он выводит?
Записан
Kivals
Модератор

ca
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 30-05-2010 15:59 » 

Речь о 7.7?
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines