Вход | Регистрация


1С:Предприятие :: 1С:Предприятие 7.7 и ранее

v7: Внутренности черного запроса 7.7 - как правильнее писать?

v7: Внутренности черного запроса 7.7 - как правильнее писать?
Я
   Злопчинский
 
29.05.18 - 03:12
Допустим есть чорный запрос

//---------------------------------------------------------
Вариант-1
.
|Груз = Регистр.Остатки.Груз;
|НомерМеста = Регистр.Остатки.Груз.НомерМеста;
...
|Условие(НомерМеста=0);

//---------------------------------------------------------
Вариант-2
.
|Груз = Регистр.Остатки.Груз;
...
|Условие(глЗапрос.Груз.НомерМеста=0);

Примечание: условие находится среди других условий в запросе
Вопрос: как правильнее писать с точки зрения производительности запроса? оттранслированные во внутреннее представление варианты написания запросов эквивалентны или будут разные..?

интересует для DBF базы, ну и для скульной не помешает

???
 
 
   Boleev
 
1 - 29.05.18 - 03:27
Я за первый вариант, но что-то мне подсказывает, что клюшкам по-барабану если не используется 1с++.
   Зуекщмшср
 
2 - 29.05.18 - 04:46
Насколько помню из своей бурной молодости, каждая лишняя точка в запросе увеличивает батхед головного мозга 1С 7.7. Я за второй вариант.
   DrZombi
 
3 - 29.05.18 - 06:19
(0) Если нужна скорость, то пиши через прямые запросы.
Если побоку на производительность, то пиши как сумеешь, много не потеряешь, любой из двух вариантов отработает с равной скоростью :)
   DrZombi
 
4 - 29.05.18 - 06:21
+(0) И помни, если у вас SQL БД, то 1С 7.7 побоку на этот факт, она все ровно все потащит в папочку темп и будет все лепить через DBF прокладку :)
   dmitryds
 
5 - 29.05.18 - 06:49
(2) это при последующей обработке в цикле
(в запросе надо получить все поля, которые будут использоваться при обработке встроенным языком, на первый уровень),

а в самом запросе - фиг знает)
   Владимир1С
 
6 - 29.05.18 - 06:59
(4) Если тащить ссылки, то да, а если в прямых запросах ссылки не выводить, будет быстрее раза в 4 - 3 .
   RKx
 
7 - 29.05.18 - 07:34
(0) Правильнее будет отобрать грузы по условию НомерМеста=0, а затем передать результат в отбор регистра.
   Shandor777
 
8 - 29.05.18 - 08:25
(0) /Внутренности чорного запроса 7.7 - как правильнее писать/
Правильнее писать "чёрного" :)
   cincout
 
9 - 29.05.18 - 08:27
Правильнее так: Внутренности черного запроса 7.7
   oslokot
 
10 - 29.05.18 - 08:36
(8) (9) Это олдскульная транскрипция. И у клюшек это именно чорный запрос, да.
 
 Рекламное место пустует
   Провинциальный 1сник
 
11 - 29.05.18 - 08:42
(10) В старых книгах, до 50-х годов, писали "чорт". На фоне в общем привычной прочей лексики это слегка шокирует.
   Зуекщмшср
 
12 - 29.05.18 - 09:15
(11) Тогда бы Боярский в фильме кричал "Тысяча чОртей"!
   vcv
 
13 - 29.05.18 - 09:38
Если SQL, то первый вариант. Его 7.7 разворачивает в нормальные join.
   Злопчинский
 
14 - 29.05.18 - 12:06
(13) допустим.
а на DBF эти запросы во что транслируются?
   Злопчинский
 
15 - 30.05.18 - 18:37
(7) Это когда припрет если оптимизировать по скорости надо будет. Но так как в частности применения набор грузов небольшой и ограничен сверху отбором по заказу - то пока улучшать смысла нет.
   Злопчинский
 
16 - 30.05.18 - 18:38
Так-с, специалист провел трассировку на DBF версии.
.
Тестировались следующие варианты
.
//*******************************************

Процедура кнВариант1()

    глЗапрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = "    
        |Номенклатура = Справочник.Номенклатура.ТекущийЭлемент;
        |Продажа = Справочник.Номенклатура.Сумма;
        |Коэффициент = Справочник.Номенклатура.БазоваяЕдиница.Коэффициент;
        |Условие(Коэффициент<>1);
        |Функция СуммаПродажа = Сумма(Продажа);
        |Группировка Номенклатура Упорядочить По Номенклатура.Код Без Групп;
        |";
    
        Если глЗапрос.Выполнить(ТекстЗапроса)<>1 Тогда Возврат; КонецЕсли;
        ТЗ = "";
        глЗапрос.Выгрузить(ТЗ,1,0);
        ТЗ.ВыбратьСтроку(,"Вариант1");

КонецПроцедуры//кнВариант1()


//*******************************************

Процедура кнВариант2()

    глЗапрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = "    
        |Номенклатура = Справочник.Номенклатура.ТекущийЭлемент;
        |Продажа = Справочник.Номенклатура.Сумма;
        |Единица = Справочник.Номенклатура.БазоваяЕдиница;
        |Условие(глЗапрос.Единица.Коэффициент<>1);
        |Функция СуммаПродажа = Сумма(Продажа);
        |Группировка Номенклатура Упорядочить По Номенклатура.Код Без Групп;
        |";
    
        Если глЗапрос.Выполнить(ТекстЗапроса)<>1 Тогда Возврат; КонецЕсли;
        ТЗ = "";
        глЗапрос.Выгрузить(ТЗ,1,0);
        ТЗ.ВыбратьСтроку(,"Вариант2");

КонецПроцедуры//кнВариант2()


//*******************************************

Процедура кнВариант3()

    глЗапрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = "    
        |Номенклатура = Справочник.Номенклатура.ТекущийЭлемент;
        |Продажа = Справочник.Номенклатура.Сумма;
        |Условие(глЗапрос.Номенклатура.БазоваяЕдиница.Коэффициент<>1);
        |Функция СуммаПродажа = Сумма(Продажа);
        |Группировка Номенклатура Упорядочить По Номенклатура.Код Без Групп;
        |";
    
        Если глЗапрос.Выполнить(ТекстЗапроса)<>1 Тогда Возврат; КонецЕсли;
        ТЗ = "";
        глЗапрос.Выгрузить(ТЗ,1,0);
        ТЗ.ВыбратьСтроку(,"Вариант3");

КонецПроцедуры//кнВариант3()
   Злопчинский
 
17 - 30.05.18 - 18:40
Далее номер пункта - это номер варианта. Нулевой пункт - общее для всех вариантов.

0) Все варианты пишут в одинаковую рабочую таблицу, одинаковое количество записей. Условия проверяется до записи в рабочую таблицу. Обрабатывается в ПостЗапросе рабочая таблица одинаково.

1) Просматривается последовательно таблица Номенклатура. Для каждой её записи производится поиск по ключу в таблице Единицы. Проверяется условие в оперативной памяти. Производится запись в рабочую таблицу, если условие - истина. Для движения по таблицам используется один и тот же объект "манипуляции" записями таблиц. Для каждой таблицы, естественно - свой. Создаются они в начале цикла. Освобождаются они в конце цикла.

2) Тоже, что и в (1). Но, на каждый поиск по ключу создаётся/освобождается объект "манипуляции" для таблицы Единицы. Процесс не очень быстрый. Т.к. выполняется просмотр (тупым перебором) в оперативной памяти схемы базы данных, созданной из файла 1Cv7.DD. Да и само создание объекта не мгновенное дело.

3) Тоже, что и в (2). Но, записи таблицы Номенклатура читаются по ДВА раза. С созданием объекта "манипуляции". С точке зрения ввода/вывода в терминальном режиме - это мелочи. Но, всё ж... :-)
   Злопчинский
 
18 - 30.05.18 - 18:49
Итого: самый быстрый вариант = Вариант1.
.
Но! Вариант2 имеет при использовании чорных запросов вполне конкретное применение. Например, когда (почему - не обсуждаем) реквизит БазоваяЕдиница не типизирован жестко (Справочник неопределенного вида, наприме,р в БазовойЕдинице может быть Спр.Единицы и Спр.ДопЕдиницы) - то адресоваться напрямую в переменную запроса к реквизиту
|Коэффициент = Справочник.Номенклатура.БазоваяЕдиница.Коэффициент;
- не получится, при исполнении запроса выругается на неправильный путь к "Коэффициент" - тогда применение Варианта2 вполне прокатит.

как-то вот так.
   Djelf
 
19 - 30.05.18 - 19:05
(16) Не помню чтобы кто-то такое мерял!
В закладки! На всякий случай...

P.S. Что только люди не делают, чтобы избежать использования 1С++, фокса или 1sqlite :)
Хотя, заказчики бывают упертые и знание штатных средств оптимизации необходимо.
   Злопчинский
 
20 - 30.05.18 - 19:31
(19) тут не вопрос в том, чтобы не использовать 1С++, фокс или скулайт - вопрос втом, что если необходимости в допсредствах нет - то не используем.
   Злопчинский
 
21 - 30.05.18 - 19:32
тот же фокс - монопольно не пашет, если только не патчить.
а по скулайту у меня есть концептуальное недопонимание начальное...
   Злопчинский
 
22 - 30.05.18 - 19:35
и еще попутно (ранее озвучивалось).
дополнительные услвоия фильтрации на вычисление функций (КОГДА) отрабатывают уже на рабочей таблице, получившейся выборки. Поэтому если в запросе нет функции (без использования КОГДА) которая возвращает ненулевое значение "на сервере" - то запрос может получиться пустой... то бишь при использовании КОГДА в опредеделенных случаях надо юзать чтото типа

|Функция Дамми = Сумма(1);//чтобы "на сервере" сформировалась выборка
   Злопчинский
 
23 - 31.05.18 - 16:58
(17) по пп 2) и 3) вместо "Тоже, что и в .." следует читать "То же, что и в..."
   Ёпрст
 
24 - 31.05.18 - 17:12
(0)
только вар 1.
Если вар 2 запустить в sql, можно и не дождаться выполнения запроса
   Ёпрст
 
25 - 31.05.18 - 17:13
а так, нужно лепить прямой запрос и забыть про чорные, навсегда.
   Ёпрст
 
26 - 31.05.18 - 17:19
Ну и это, Чебур, ты для чорных запросов, хоть делаешь
глПередВыполнениемЗапроса ?
   Ёпрст
 
27 - 31.05.18 - 17:19
который выкидывает лишние переменные с текста запроса ?
Особенно актуально в типовых отчетах.
   Злопчинский
 
28 - 31.05.18 - 17:40
(26) Не не делаю, если есть - скинь сюда
Я сейчас кропаю очередную нетленку ;-)
Запросы формирую динамически, минимум необходимого в текст запроса пихаю.
   Злопчинский
 
29 - 31.05.18 - 17:54
(27) у меня есть глобальная непонятка и я постоянно стремаюсь...

Когда есть переменные запроса, не участвующие в группировках, но нужные в результатах запроса

1. Какой в этом смысл, ведь на уровне группировки переменная запроса, не участвующая в группировке, не будет иметь смысла - так?
2. Переменные запроса имеют смысл только на том уровне группировки, которая соответствует "уровню" переменной? - так? то есть если мы обращаемся к переменной запроса типа Запрос.ЧтоТоИзРеквизитовШапкиДокумента - то это будет иметь смысл только если мы находимся на уровне группировки "Документ" - так?
   vcv
 
30 - 31.05.18 - 20:31
(28) Не моё ли поделие имеется в виду?
http://catalog.mista.ru/public/64620/
   vcv
 
31 - 31.05.18 - 20:41
(29) >> Какой в этом смысл
Глобальный смысл сократить индексное выражение. По всем группировкам 1С делает один сборный индекс и он, к сожалению, ограничен по длине выражения. Большое количество группировок (штук десять и меньше, если есть строковые значения) приводит к ошибке "Длина индекса превышает максимальную длину и не может быть уменьшена". Ну и проще индекс - быстрее обработка запроса.

>> Переменные запроса имеют смысл только на том уровне
>> группировки, которая соответствует "уровню" переменной?

Примерно так. Удобно, когда нужно, например, в отчёте с номенлатурой показать артикул, код, базовую единицу... Это всё можно получить запросом. Будет быстрее, чем в процессе вывода таблицы отчёта для каждой строки отчёта дёргать базу для получения реквизитов номенклатуры.
   Djelf
 
32 - 31.05.18 - 21:09
Могу быть не прав, но...

- смотрим на индекс в DD,
- если мы в какой то индекс можем попасть, указываем условия в порядке индекса
- если индекса нет, указываем условия по такому порядку чтобы выборка поменьше (какой индекс выбрать склад или номенклатура?. Это зависит от того сколько складов и сколько номенклатуры)

А еще можно вырубить 1с во время запроса и посмотреть что там за данные и индексы оно сотворило...

P.S. А sqlite это ты зря! (upsert уже почти есть, но это не так интересно для баз 7.7 /для внешних вкусно/). А скоро будет и с оконными функциями. Вкусно, вкусно...
   Злопчинский
 
33 - 31.05.18 - 21:27
(32) да я ж только за! скулайт. у мну непонимание начальное концептуальное есть - а где почитать с азов, так чтобы понимать какие операторы в самом начале примененяи скулайта писать (что там как определять таблицы в мемори и прочее - как-то не встречалось.
 
 
   Djelf
 
34 - 31.05.18 - 21:40
(33) Вечная недоделка... Времени на нее не очень есть ;(
https://cloud.mail.ru/public/DsqW/V4c39Td9o
   Злопчинский
 
35 - 31.05.18 - 21:54
(34) ну значит надо бросать и переходить на снеговика, там, говорят, как в раю - всё уже есть и практически даром...
   Злопчинский
 
36 - 31.05.18 - 23:19
(31) Как моэно сократить "индексное выражение" если речь идет о переменных, не входящих ни в группировки, ни в условия?
   Boleev
 
37 - 01.06.18 - 02:17
Нетленка на 7.7? почему на на перфокартах?
   Злопчинский
 
38 - 01.06.18 - 02:37
(37) При необходимости если упереться я могу для БЭСМ-6 на forex (вроде так назывался) налабать... или на ADABASe.. или на ассемблере для ЕСок, на перфокартах не смогу - бармалея в личном распоряжении нет...
   Злопчинский
 
39 - 01.06.18 - 02:38
(37) .. и потому что - самая короткая дорога - та, которую знаешь.. ;-)
   Maniac
 
40 - 01.06.18 - 02:40
самое быстрое если номер груза - основное к чему регулярно обращаются - сделать его измерением.
Вижу что итак регистр остатков в котором есть груз - какая то офигенная нетленка
   Maniac
 
41 - 01.06.18 - 02:41
а так в челом если Номер места тип число. то вообще поуху.
Этот тип не ресурсоемкий.
Через много точек - скорость зависит от того на каком месте это измерение Груз в регистре. Включена ли галка на нем
   Maniac
 
42 - 01.06.18 - 02:43
Если оно там 5-6-7 по счету, есть смысл задуматься о том чтобы сделать новый регистр.
Семерка и куча измерений - начинает вешаться и на запись и на чтение.
Идеально для 77 это 5 измерений, не больше.
А лучше 4
   Maniac
 
43 - 01.06.18 - 02:45
вообще 77 удивительная платформа, в которое от положения регистре может вершится судьба
   Maniac
 
44 - 01.06.18 - 02:52
Если память не отшибло в типовой ТИС измерения склад и номенклатура располодены так что если сдвинуть номенклатуру на первое место и переписать методы Остатки и СводныОстаток то скорость просто без использования даже 1С++ может в тысячу раз увеличится и размер дбф и индекса уменьшиться
   Maniac
 
45 - 01.06.18 - 02:55
Братан если ты не в курсе того что я написал. То ты полжизни работы на 77 даже потратил зря.Сдвигать измерения в 1С без потери данных, и всего навсего 2 метода в 77 где надо местами переменные поменять, и то их там будет с десяток.
Переидексация базы автоматическая, и жизнь играет в новых красках.
   vcv
 
46 - 01.06.18 - 05:41
(44) Легенды нашего городка?
С быстродействием еще ладно. Изменяется по факту. В зависимости от обращений к регистру. При проведении документа фирма, склад и номенклатура известны, значит все компоненты сборного индекса есть. От перестановки мест в индексе вряд ли что-то сильно поменяется. Всё остальное в зависимости от данных и алгоритмов. Если переместить номенклатуру на первое место, получение отчёта по складским остаткам должно замедлиться. Пропорционально количеству фирм и складов.

Но, конечно, перестановка измерений меняет индекс. Последствия могут быть серьёзные в обе стороны. Когда на SQL начинаешь пользоваться прямыми запросами, в полной мере осознаёшь разницу между index seek, index scan, table scan.

А размер файлов-то почему изменится? Не вижу к этому вообще никаких предпосылок.
   МихаилМ
 
47 - 01.06.18 - 06:03
эта тема обсуждалась на этом форуме лет 10 назад.
и приводились примеры, что конструкцией
условие (запрос.)  лучше не пользоваться , тк иногда выдаётся неверный результат.
   Злопчинский
 
48 - 01.06.18 - 11:30
(40) Маня, ты не поверишьЮ но в складской логистике - это сплошь и рядом. и я бы даже сказал - норма. Мир ведь не замкнулся на твоих лавочниках с автозапчастями.
   Злопчинский
 
49 - 01.06.18 - 11:31
(47) "условие (запрос.)  лучше не пользоваться , тк иногда выдаётся неверный результат."
- а не помнишь в чем там было дело?
 
 Рекламное место пустует
   Эльниньо
 
50 - 01.06.18 - 11:52
(37) Перфокарта - вчерашний день. Перфолента и только перфолента.
   Salimbek
 
51 - 01.06.18 - 12:20
(33) Как-то так:
    база = СоздатьОбъект("SQLiteBase");
...
    база.Открыть(":memory:");
    рс = база.НовыйЗапрос();
...
    ТекстЗапросаРекИД="
    |select d.iddoc iddoc, substr(Комментарий,8) comment
    |from (select iddoc from Журнал where DATE between :НачДата and :КонДата and iddocdef=:ВидДокумента.ОприходованиеТМЦ and closed=1) G
    |    inner join Документ_ОприходованиеТМЦ d
    |        on G.iddoc=d.iddoc
    |where substr(Комментарий,1,7)='rec_id='";
    инТЗ=СоздатьОбъект("ИндексированнаяТаблица");
    рс.Подставлять("НачДата",Формат(НачМесяца(НачДата),"ДГГГГММДД"));
    рс.Подставлять("КонДата",Формат(КонДата,"ДГГГГММДД"));
    инТЗ=рс.ВыполнитьЗапрос(ТекстЗапросаРекИД,СоздатьОбъект("ИндексированнаяТаблица"));
    инТЗ.ДобавитьИндекс("их_ид","*iddoc");

и обработка 1sqlite.ert для отладки и оптимизации запросов
   Злопчинский
 
52 - 01.06.18 - 12:34
(51) база.Открыть(":memory:");
- это перед каждым запросом надо делать? надо после запроса как-то "закрывать"..? или достаточно сделать база.Открыть(":memory:"); - один раз на весь сеанс и шпарить любые запросы?
   Salimbek
 
53 - 01.06.18 - 13:01
(52) Код из внешней обработки для стандартной ТиС, поэтому открывается один раз в ПриОткрытии, база - переменная модуля формы.
Вообще, как мы помним, 1С-ка не мультизадачная, поэтому даже рс = база.НовыйЗапрос(); можно вынести в ПриОткрытии и дальше все запросы делать с использованием этого одного РекордСета.

Был правда случай из практики - когда пришлось одновременно два запроса в цикл дергать, там было проще сделать два РС-а с разными подготовленными запросами.

...

Подготовленные запросы это так (Добавляем в документ товары из файла, по полученному ШтрихКоду):

    ТекстЗапроса="select parentext [Товар :Справочник.Номенклатура] from Справочник_Единицы where Штрихкод=@ШК";
    рс.Подготовить(ТекстЗапроса);
    Табличка=стДок.Document_Table;
    тзДок = СоздатьОбъект("ТаблицаЗначений");
    Док.ВыгрузитьТабличнуюЧасть(тзДок);
    Для Сч=1 По Табличка.Количество() Цикл
        тзДок.НоваяСтрока();
        лкСтрока=Табличка.Получить(Сч);
        рс.УстановитьПараметр("@ШК", лкСтрока.Barcode);
        тз=рс.Выполнить();
        тзДок.ВидТМЦ = Перечисление.ВидыТМЦ.Товар;
        тзДок.Номенклатура = тз.ПолучитьЗначение(1,1).ТекущийЭлемент();
   Salimbek
 
54 - 01.06.18 - 13:07
Еще пример запроса из той же обработки, демонстрирует использование доп_полей (1SQLite дает возможность запроса к индексированному выражению, как к отдельному полю, для гарантированного попадания)
Выбираем все документы за Период из Журнала складских документов с отбором по указанному Складу
    ТекстЗапроса="
    |select G.iddocdef iddocdef, G.iddoc iddoc, CHILDDATE, str2id(CHILDTIME)/10000 chTime, G.iddocdef || G.iddoc [d :Документ],
    |    shk
    |    ,R.Количество * (1-2*R.DEBKRED) Kol
    |from (select * from Журнал where DATE between :НачДата and :КонДата) G
    |    inner join __1S_crdoc O 
    |        on o.idx_MDID_PARENTVAL_CHILDDATE_CHILDTIME_CHILDID=
    |                :ГрафаОтбора.Склад || 'B1  1J' || :Склад || '        '||g.DATE||g.TIME||g.iddoc
    |    inner join Регистр_ОстаткиТМЦ R on g.iddoc=R.iddoc
    |    left join tSh S
    |    ON R.Номенклатура=S.pid
    |Where R.Склад=:Склад
    |order by CHILDDATE, CHTIME, IDDOC
    |";
   Djelf
 
55 - 01.06.18 - 13:08
(52) Если у тебя глБаза то только один раз.
Если лБаза в обработке то надо инициализировать.
Закрывать не обязательно - сама закроется при уничтожении объекта.


Список тем форума
Рекламное место пустует  Рекламное место пустует
ВНИМАНИЕ! Если вы потеряли окно ввода сообщения, нажмите Ctrl-F5 или Ctrl-R или кнопку "Обновить" в браузере.
Рекламное место пустует