Имя: Пароль:
1C
1C 7.7
v7: Внутренности черного запроса 7.7 - как правильнее писать?
, , ,
0 Злопчинский
 
29.05.18
03:12
Допустим есть чорный запрос

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

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

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

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

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

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

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

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

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

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

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

P.S. А sqlite это ты зря! (upsert уже почти есть, но это не так интересно для баз 7.7 /для внешних вкусно/). А скоро будет и с оконными функциями. Вкусно, вкусно...
33 Злопчинский
 
31.05.18
21:27
(32) да я ж только за! скулайт. у мну непонимание начальное концептуальное есть - а где почитать с азов, так чтобы понимать какие операторы в самом начале примененяи скулайта писать (что там как определять таблицы в мемори и прочее - как-то не встречалось.
34 Djelf
 
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) Как моэно сократить "индексное выражение" если речь идет о переменных, не входящих ни в группировки, ни в условия?
37 Boleev
 
01.06.18
02:17
Нетленка на 7.7? почему на на перфокартах?
38 Злопчинский
 
01.06.18
02:37
(37) При необходимости если упереться я могу для БЭСМ-6 на forex (вроде так назывался) налабать... или на ADABASe.. или на ассемблере для ЕСок, на перфокартах не смогу - бармалея в личном распоряжении нет...
39 Злопчинский
 
01.06.18
02:38
(37) .. и потому что - самая короткая дорога - та, которую знаешь.. ;-)
40 Maniac
 
01.06.18
02:40
самое быстрое если номер груза - основное к чему регулярно обращаются - сделать его измерением.
Вижу что итак регистр остатков в котором есть груз - какая то офигенная нетленка
41 Maniac
 
01.06.18
02:41
а так в челом если Номер места тип число. то вообще поуху.
Этот тип не ресурсоемкий.
Через много точек - скорость зависит от того на каком месте это измерение Груз в регистре. Включена ли галка на нем
42 Maniac
 
01.06.18
02:43
Если оно там 5-6-7 по счету, есть смысл задуматься о том чтобы сделать новый регистр.
Семерка и куча измерений - начинает вешаться и на запись и на чтение.
Идеально для 77 это 5 измерений, не больше.
А лучше 4
43 Maniac
 
01.06.18
02:45
вообще 77 удивительная платформа, в которое от положения регистре может вершится судьба
44 Maniac
 
01.06.18
02:52
Если память не отшибло в типовой ТИС измерения склад и номенклатура располодены так что если сдвинуть номенклатуру на первое место и переписать методы Остатки и СводныОстаток то скорость просто без использования даже 1С++ может в тысячу раз увеличится и размер дбф и индекса уменьшиться
45 Maniac
 
01.06.18
02:55
Братан если ты не в курсе того что я написал. То ты полжизни работы на 77 даже потратил зря.Сдвигать измерения в 1С без потери данных, и всего навсего 2 метода в 77 где надо местами переменные поменять, и то их там будет с десяток.
Переидексация базы автоматическая, и жизнь играет в новых красках.
46 vcv
 
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) Перфокарта - вчерашний день. Перфолента и только перфолента.
51 Salimbek
 
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:"); - один раз на весь сеанс и шпарить любые запросы?
53 Salimbek
 
01.06.18
13:01
(52) Код из внешней обработки для стандартной ТиС, поэтому открывается один раз в ПриОткрытии, база - переменная модуля формы.
Вообще, как мы помним, 1С-ка не мультизадачная, поэтому даже рс = база.НовыйЗапрос(); можно вынести в ПриОткрытии и дальше все запросы делать с использованием этого одного РекордСета.

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

...

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

    ТекстЗапроса="select parentext [Товар :Справочник.Номенклатура] from Справочник_Единицы where Штрихкод=@ШК";
    рс.Подготовить(ТекстЗапроса);
    Табличка=стДок.Document_Table;
    тзДок = СоздатьОбъект("ТаблицаЗначений");
    Док.ВыгрузитьТабличнуюЧасть(тзДок);
    Для Сч=1 По Табличка.Количество() Цикл
        тзДок.НоваяСтрока();
        лкСтрока=Табличка.Получить(Сч);
        рс.УстановитьПараметр("@ШК", лкСтрока.Barcode);
        тз=рс.Выполнить();
        тзДок.ВидТМЦ = Перечисление.ВидыТМЦ.Товар;
        тзДок.Номенклатура = тз.ПолучитьЗначение(1,1).ТекущийЭлемент();
54 Salimbek
 
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
    |";
55 Djelf
 
01.06.18
13:08
(52) Если у тебя глБаза то только один раз.
Если лБаза в обработке то надо инициализировать.
Закрывать не обязательно - сама закроется при уничтожении объекта.