Заметочки про 1С:Предприятие 8 (редакция 22.06.2012)

11.07.13

Разработка - Механизмы платформы 1С

За время программирования на 8.х, накопилось пока немного материала, но как мне кажется очень интересного. Появились простые решения, которые в более сложной реализации встречаются в типовых конфигурациях и в некоторых публикациях на Infostart'е. Собственно в статье речь пойдет об этих решениях.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
КодВОднуСтроку.epf
.epf 7,47Kb
627
627 Скачать (1 SM) Купить за 1 850 руб.
Пример 1
.epf 7,28Kb
1230
1230 Скачать (1 SM) Купить за 1 850 руб.
Пример 2
.epf 8,52Kb
543
543 Скачать (1 SM) Купить за 1 850 руб.
Пример 3 без оптимизации
.epf 9,72Kb
476
476 Скачать (1 SM) Купить за 1 850 руб.
Пример 3 с оптимизацией
.epf 10,34Kb
467
467 Скачать (1 SM) Купить за 1 850 руб.
Гостинец от Ish_2
.epf 9,91Kb
422
422 Скачать (1 SM) Купить за 1 850 руб.
Пример 4
.epf 8,13Kb
449
449 Скачать (1 SM) Купить за 1 850 руб.
Пример 5
.epf 7,78Kb
375
375 Скачать (1 SM) Купить за 1 850 руб.
COM MONITOR
.epf 23,63Kb
369
369 Скачать (1 SM) Купить за 1 850 руб.
Пример 6 для COM Monitor
.epf 271,79Kb
511
511 Скачать (1 SM) Купить за 1 850 руб.
Пример 7
.epf 9,47Kb
294
294 Скачать (1 SM) Купить за 1 850 руб.
Пример 8
.erf 13,23Kb
270
270 Скачать (1 SM) Купить за 1 850 руб.
Пример 9
.erf 12,69Kb
247
247 Скачать (1 SM) Купить за 1 850 руб.
Пример 10
.epf 10,76Kb
52
52 Скачать (1 SM) Купить за 1 850 руб.
Только качественный контент

Оглавление

Если вы это всё уже знаете, то, пожалуйста, не кидайте в автора грязью. Танки грязи не боятся. Smile

Но всё-таки я надеюсь вас чем-нибудь удивить.

В подтверждение заметок описанных в статье прикладываю примеры и материалы. Всегда можно проверить.

Для вступления думаю достаточно. Начнем.       


Про циклы в одну строку

Первым номером нашей программы выступает код добавления (копирования) строк из одной таблицы значений в другую ТЗ или из одной табличной части в другую ТЧ. Ну, и т.д. Т.е. строки из обоих источников объединяются, совпадающие по имени колонки заполняются.

Для каждого СтрокаТЗ Из Таблица1 Цикл ЗаполнитьЗначенияСвойств(Таблица2.Добавить(), СтрокаТЗ) КонецЦикла;


Соответственно код добавления элементов из массива в массив будет такой.

Для каждого ЭлементМассива Из Массив1 Цикл Массив2.Добавить(ЭлементМассива) КонецЦикла;


Всего одна команда в цикле - что может быть проще?

Наверное, вы уже обратили внимание на запись циклов в одну строку. Так программный код выполняется несколько быстрее. Всё дело в том, что в строках есть дополнительные данные, которые используются, например, при отладке. Меньше строк - меньше дополнительных данных. Это прекрасно видно, если смотреть замер производительности в режиме отладки - цикл в строке Для из 10000 повторов записанный обычной структурой будет выполнен 10001 раз, а записанный в 1 строку будет выполнен 1 раз. Разумеется, что при этом результат выполнения программного кода будет абсолютно одинаковый, а вот время выполнения будет разное. Не верится? Смотрим "Пример 1".
Скачать Пример 1...

Следует заметить, что править такую форму записи очень сложно. Поэтому, если команды отрабатываются 1 раз, то нет особого смысла записывать их в 1 строку друг за другом.

Также "тонким" моментом будет использование команды ОбработкаПрерыванияПользователя(). Если в цикле, записанном в 1 строку, используется данная команда, то вероятность срабатывания прерывания выполнения программы по Ctrl+Break становится не четким. Ну, может за исключением тех случаев, когда в цикле кроме этой других команд нет. Smile

Хочу сразу обратить ваше внимание на комментарии awa к этой статье. Всё сразу станет понятнее.

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

Вернуться к оглавлению...


Про быстрые массивы

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

// РазбираемаяСтрока - строка исходного текста
// Разделитель - разделитель элементов строки

ЗначениеИзСтрокиВнутр("{""#"",51e7a0d2-530b-11d4-b98a-008048da3034,{0,{""S"",""" + СтрЗаменить(СтрЗаменить(РазбираемаяСтрока, """", """"""), Разделитель, """},{""S"",""") + """}}}");


Вот код для числовых значений.

ЗначениеИзСтрокиВнутр("{""#"",51e7a0d2-530b-11d4-b98a-008048da3034,{0,{""N""," + СтрЗаменить(РазбираемаяСтрока, Разделитель, "},{""N"",") + "}}}");


Посмотреть, как это работает можно здесь, здесь и здесь.
В (150) комментарии к статье было высказано предположение, что данный метод не эффективен, поэтому был добавлен "Пример 7". Действительно, на коротких строках предложенное в (150) комментарии решение с разбором строки эффективнее, но сложнее в исполнении. Ещё более эффективное решение и ещё более сложное в исполнении Smile читаем ниже...
Скачать Пример 7...

 

Так, так, так. А вот довольно шустренький программный код для сворачивания элементов массива. Результат записывается в НовыйМассив.

НовыйМассив = Новый Массив; Соответствие = Новый Соответствие;
Для каждого
ЭлементМассива Из Массив Цикл Соответствие.Вставить(ЭлементМассива) КонецЦикла;
Для каждого
КлючИЗначение Из Соответствие Цикл НовыйМассив.Добавить(КлючИЗначение.Ключ) КонецЦикла;


Для сравнения в "Пример 4" приведено 4 варианта реализации сворачивания массива: через массив, через таблицу значений, через соответствие и вариант, реализованный в типовых конфигурациях 1С. Поэкспериментируйте и выберите тот, что вам больше понравится.
Скачать Пример 4...

 

Если вдруг понадобится отсортировать элементы в массиве, то быстро это можно сделать так:

СписокЗначений = Новый СписокЗначений;
СписокЗначений.ЗагрузитьЗначения(Массив);
СписокЗначений.СортироватьПоЗначению();
Массив = СписокЗначений.ВыгрузитьЗначения();

В некоторых случаях больше подойдет сортировка не по значению, а по представлению.

Вернуться к оглавлению...


Про длинные строки

Получить строку из пробелов нужной длины можно собирая пробелы в цикле. Но можно использовать следующую конструкцию:

// Получаем строку пробелов длиной 10000 символов
СтрокаПробелов = СтрЗаменить(Формат(0, "ЧЦ=100; ЧН=; ЧВН=; ЧГ="), "0",
                
СтрЗаменить(Формат(0, "ЧЦ=100; ЧН=; ЧВН=; ЧГ="), "0", " ")); 


Интересное наблюдение при работе со строками большой длины можно сделать в "Пример 5". Использование трехуровневой буферизации может дать ускорение в десятки и даже тысячи раз. Код может выглядеть так:

Данные = "";
Результат = "";
Результат1 = "";
Результат2 = "";
// Получаем Данные и записываем в Результат
Пока ПолучитьДанные(Данные) Цикл
   
Результат2 = Результат2 + Данные;
    Если
СтрДлина(Результат2) > 100 Тогда
       
Результат1 = Результат1 + Результат2;
       
Результат2 = "";
        Если
СтрДлина(Результат1) > 10000 Тогда
           
Результат = Результат + Результат1;
           
Результат1 = "";
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

Результат = Результат + Результат1 + Результат2;


Конечно, и здесь цикл можно записать в одну строку, но это не сделано только для сохранения читаемости программного кода в статье.
Скачать Пример 5...

В (302) комментарии к статье приведен интересный код для разбора длинных текстовых строк, позволяющий проводить предварительную обработку данных, например, перед помещением их в массив. Применительно к задаче помещения данных в массив на больших объемах данных он работает конечно медленнее, чем код описанный в разделе Про быстрые массивы, но возможность предварительной обработки данных дорогого стоит. Предлагаю рассмотреть альтернативное решение без использования объекта ТекстовыйДокумент. Оно конечно сложнее в исполнении, но эффективнее в работе и также позволяет добавить предварительную обработку данных, например, перед помещением их в массив.

ДлинаСтроки = СтрДлина(РазбираемаяСтрока);

Если
ДлинаСтроки > 1000 Тогда
   
// Порежем строку на блоки для более эффективного поиска
   
МассивСтрок = Новый Массив;
   
Индекс = 1;
    Пока
Индекс <= ДлинаСтроки Цикл
       
МассивСтрок.Добавить(Сред(РазбираемаяСтрока, Индекс, 1000));
       
Индекс = Индекс + 1000;
    КонецЦикла;

   
мИсходныйКод = МассивСтрок[0];
   
ГраницаКода = МассивСтрок.ВГраница();
Иначе
   
мИсходныйКод = РазбираемаяСтрока;
   
ГраницаКода = 0;
КонецЕсли;


мСтрок = Новый Массив;
ИндексКода = 0;
ДлинаРазделителя = СтрДлина(Разделитель);
НеПоследняяСтрока = Истина;

Пока
НеПоследняяСтрока Цикл
   
Позиция = Найти(мИсходныйКод, Разделитель);
    Пока
Позиция = 0 Цикл
        Если
ИндексКода = ГраницаКода Тогда
           
// Последний элемент
           
Позиция = СтрДлина(мИсходныйКод);
           
НеПоследняяСтрока = Ложь;
            Прервать;
        КонецЕсли;

       
ИндексКода = ИндексКода + 1;
       
мИсходныйКод = мИсходныйКод + МассивСтрок[ИндексКода];
       
Позиция = Найти(мИсходныйКод, Разделитель);
    КонецЦикла;

   
мСтрок.Добавить(Лев(мИсходныйКод, Позиция));
   
мИсходныйКод = Сред(мИсходныйКод, Позиция + ДлинаРазделителя);
КонецЦикла;

Возврат
мСтрок;


Посмотреть как это работает можно здесь и здесь.

 

Если вы подумали, что эта статья только об оптимизации производительности, то это не так. Статья об оптимизации производительности здесь, и не смотря на то, что статья посвящена 7.7, многие приемы оптимизации работают и в 8.х.

Вернуться к оглавлению...


Про типы данных. Динамическая настройка колонок табличного поля

Иногда бывает нужно проверить тип данных какого-либо ревизита. Для типов данных без квалификаторов проверку типа данных легко сделать с помощью ОписаниеТипов. А вот для типов данных Число, Строка и Дата можно использовать другую конструкцию с использованием массива типов. Вот пример для динамической настройки табличного поля. В примере использованы оба способа сравнения типов.

ТипЧисло = Тип("Число");
ОписаниеТипаБулево = Новый ОписаниеТипов("Булево");

мВыводитьПодвал = Ложь;
ТабличноеПоле.СоздатьКолонки();
КолонкиИсточника = ТабличноеПоле.Значение.Колонки;

// Отобразим булево как галочки, а отрицательные числа красным
Для каждого КолонкаТЧ Из ТабличноеПоле.Колонки Цикл
   
ИмяКолонкиТЧ = КолонкаТЧ.Имя;
   
ТипЗначенияКолонки = КолонкиИсточника[ИмяКолонкиТЧ].ТипЗначения;
    Если
ТипЗначенияКолонки = ОписаниеТипаБулево Тогда
       
КолонкаТЧ.ДанныеФлажка = КолонкаТЧ.Данные;
       
КолонкаТЧ.Данные = "";
    ИначеЕсли
ИмяКолонкиТЧ <> "НомерСтроки" Тогда
       
МассивТипов = ТипЗначенияКолонки.Типы();
        Если
МассивТипов.Количество() = 1 и МассивТипов[0] = ТипЧисло Тогда
           
КолонкаТЧ.ВыделятьОтрицательные = Истина;
           
КолонкаТЧ.ОтображатьИтогиВПодвале = Истина;
           
КолонкаТЧ.ГоризонтальноеПоложениеВПодвале = ГоризонтальноеПоложение.Право;
           
мВыводитьПодвал = Истина;
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

ТабличноеПоле.Подвал = мВыводитьПодвал;


К вопросу "Почему не воспользоваться методом СодержитТип?". Метод СодержитТип не дает однозначного ответа на вопрос "Какой тип реквизита?". Он только подтверждает, что реквизит может быть, например, числом. А если реквизит составного типа?

Как это работает можно посмотреть здесь.

Вернуться к оглавлению...


Про типы данных. Расчет сумм по выделенным ячейкам табличного поля

В некоторых типовых конфигурациях 1С и публикациях в интернете используется очень удобный сервис "расчет сумм по выделенным ячейкам табличного поля". К сожалению все попавшие на глаза варианты реализации работают "неверно" при подсчете сумм по накладывающимся выделенным областям. При подсчете суммы из ячеек в персекающихся областях учитываются несколько раз.

Предлагаю простенькую функцию, в которой данный "эффект" устранен.

Функция РасчетСуммыПоЯчейкам(ТабличноеПоле) Экспорт

   
Сумма = 0;
   
КоличествоСумм = 0;
   
СоответствиеЯчеек = Новый Соответствие;
   
ОписаниеТипов = Новый ОписаниеТипов("Число");

    Для Каждого
ВыделеннаяОбласть Из ТабличноеПоле.ВыделенныеОбласти Цикл
        Для
Индекс1 = ВыделеннаяОбласть.Лево По ВыделеннаяОбласть.Право Цикл
            Для
Индекс2 = ВыделеннаяОбласть.Верх По ВыделеннаяОбласть.Низ Цикл
               
Область = ТабличноеПоле.Область(Индекс2, Индекс1, Индекс2, Индекс1);
               
Значение = ОписаниеТипов.ПривестиЗначение(Область.Текст);
               
СоответствиеЯчеек.Вставить(Область.Имя, Значение);
            КонецЦикла;
        КонецЦикла;
    КонецЦикла;

    Для каждого
Ячейка Из СоответствиеЯчеек Цикл
       
Значение = Ячейка.Значение;
        Если
Значение <> 0 Тогда
           
Сумма = Сумма + Значение;
           
КоличествоСумм = КоличествоСумм + 1;
        КонецЕсли;
    КонецЦикла;

   
КоличествоВыделено = СоответствиеЯчеек.Количество();
    Если
КоличествоВыделено > 1 Тогда
       
ТекстИтогов = " Выделено ячеек: " + КоличествоВыделено
            + "    Просуммировано ячеек: " + КоличествоСумм
            + "    Итого по выделенным ячейкам: " + Сумма;
    Иначе
       
ТекстИтогов = "";
    КонецЕсли;

    Возврат
ТекстИтогов;

КонецФункции
// РасчетСуммыПоЯчейкам()


Использование метода ПривестиЗначение вместо встречающегося в типовых конфигурациях преобразования через Попытка, дает в среднем ускорение на преобразовании типов в 4 раза. А использование отложенного вызова функции расчета суммы всего лишь на 0.2 секунды с легкостью решает проблему с задержками при выделении пользователем большого количества ячеек.

Посмотреть как это работает можно здесь и здесь.

Ещё про работу с типами данных можно почитать ниже...

Вернуться к оглавлению...


Про хитрые запросы. Не стандартное использование итогов

А что сейчас? А сейчас запросы. Не все конечно, а несколько каких-нибудь простеньких и интересненьких. Например, построение запросом двухуровневого дерева структуры задолженности для формы элемента справочника Контрагенты. Исходим из того, что чем меньше команд, тем быстрее работает. Ну, обычно быстрее. Ведь 1С это все-таки интерпретатор.

Итак, строим запросом дерево по структуре задолженности как на картинке ниже, смотрим закладку Задолженность. На закладке добавлено табличное поле с деревом значений Задолженность.

Получаем в детальных строках договоры контрагентов, а в итоговых строках организации. Приведенный ниже в качестве примера программный код будет работать в УТ и УПП. Для остальных конфигураций код запроса нужно немного подправить.

Запрос = Новый Запрос(
   
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
    | ДоговорыКонтрагентов.Организация КАК Организация,
    | ДоговорыКонтрагентов.Ссылка КАК СтруктураДоговоров,
    | -ЕСТЬNULL(ВзаиморасчетыОстатки.СуммаВзаиморасчетовОстаток, 0) КАК Сумма
    |ИЗ
    | Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
    |  ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ВзаиморасчетыСКонтрагентами.Остатки(
    |       , Контрагент = &Контрагент) КАК ВзаиморасчетыОстатки
    |  ПО ДоговорыКонтрагентов.Ссылка = ВзаиморасчетыОстатки.ДоговорКонтрагента
    |ГДЕ
    | ДоговорыКонтрагентов.Владелец = &Контрагент
    |
    |УПОРЯДОЧИТЬ ПО
    | Организация,
    | СтруктураДоговоров
    |ИТОГИ
    | Организация КАК СтруктураДоговоров,
    | СУММА(Сумма)
    |ПО
    | Организация"
);
Запрос.УстановитьПараметр("Контрагент", Ссылка);
Задолженность = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);


Получилось простенько и симпатично.

В итогах Организация используется без агрегатной функции - это возможно потому, что по Организации выполняется группировка. Ещё примеры построения двухуровневого дерева можно посмотреть здесь.

Вернуться к оглавлению...


Про хитрые запросы. Тэта-соединения 1

Кажется тема с запросами получилась интересной. Тогда ещё один примерчик "Пример 2", который можно подержать в руках - изменение курсов валют с группировкой по месяцам.

 

Запрос = Новый Запрос(
   
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |   КурсыВалют.Период КАК Период1,
    |   МАКСИМУМ(ЕСТЬNULL(КурсыВалют1.Период, КурсыВалют.Период)) КАК Период2
    |ПОМЕСТИТЬ Соединения
    |ИЗ
    |   РегистрСведений.КурсыВалют КАК КурсыВалют
    |       ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют1
    |       ПО КурсыВалют.Валюта = КурсыВалют1.Валюта
    |           И КурсыВалют.Период > КурсыВалют1.Период
    |           И (КурсыВалют1.Валюта = &Валюта)
    |ГДЕ
    |   КурсыВалют.Валюта = &Валюта
    |
    |СГРУППИРОВАТЬ ПО
    |   КурсыВалют.Период
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |   КурсыВалют.Период КАК Период,
    |   НАЧАЛОПЕРИОДА(КурсыВалют.Период, МЕСЯЦ) КАК ПериодДляИтогов,
    |   КурсыВалют.Курс,
    |   КурсыВалют.Курс - КурсыВалют1.Курс КАК ИзменениеКурса
    |ИЗ
    |   РегистрСведений.КурсыВалют КАК КурсыВалют
    |       ВНУТРЕННЕЕ СОЕДИНЕНИЕ Соединения КАК Соединения
    |           ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют1
    |           ПО Соединения.Период2 = КурсыВалют1.Период
    |               И (КурсыВалют1.Валюта = &Валюта)
    |       ПО КурсыВалют.Период = Соединения.Период1
    |           И (КурсыВалют.Валюта = &Валюта)
    |ИТОГИ
    |   ПериодДляИтогов КАК Период,
    |   СУММА(ИзменениеКурса)
    |ПО
    |   ПериодДляИтогов"
);
Запрос.УстановитьПараметр("Валюта", Валюта);
КурсыВалют = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); 


Аналогично можно построить и другие запросы, в которых отслеживается изменение значений показателей, например, изменение цен.
Скачать Пример 2...

Вернуться к оглавлению...


Про хитрые запросы. Тэта-соединения 2

"Продолжаем разговор". В качестве ещё одного примера работы с запросами добавлен "Пример 3", в котором реализовано получение периодов действия установленных значений периодических регистров сведений. Перечитал предыдущее предложение - получилось немного тяжеловато, ну, да ладно. Предложенное решение в "Пример 3" может быть использовано, например, при решении задач по расчету заработной платы или при начислениях в ЖКХ.

Пример 3

Фишка этого запроса в том, чтобы убрать повторяющиеся данные из цепочки, а оставить только точки перехода с датами, когда данный переход был выполнен.
Т.е. для цепочки значений 0, 0, 1, 1, 1, 0, 0, 0, 1
должны остаться только значения 0, 1, 0, 1 и соответственно даты, когда значения в цепочке поменялись.

И несколько слов об оптимизации тэта-соединений. Во вложении 3 варианта реализации с использованием запросов, поэтому в статье текстов этих запросов нет - очень объемно получается. При больших объемах информации оптимизированный вариант запросов дает значительное ускорение, особенно в файловой версии. Это собственно и не удивительно, оптимизатор SQL сервера делает своё дело. Автором одного из вариантов является Ish_2 - это вариант "Гостинец".

Скачать Пример 3 без оптимизации...
Скачать Пример 3 с оптимизацией...
Скачать Гостинец от Ish_2...

Суть оптимизации сводится к уменьшению количества записей используемых в соединениях, аналогами которых являются нарастающие итоги. Подробнее про подобный подход можно почитать здесь.

Также интересный эффект получается при использовании индексов для временных таблиц. Попробуйте поиграть с объемами данных и галочками "Использовать индексы в запросе". Обещаю весьма неожиданный результат. Smile

Так уж получилось, что большинство комментариев к данной статье посвящено именно этому запросу. Видимо в нем есть тайное знание доступное теперь всем желающим.

Ещё про запросы можно посмотреть здесь, а про запросы с датами можно посмотреть здесь.

Вернуться к оглавлению... 


Про хитрые запросы. Тэта-соединения 3. Строки неограниченной длины

Делал загрузку прайсов из Excel. Если прайс и справочник Номенклатура маленькие, то конечно всё работает сравнительно быстро. Несколько секунд и сопоставление выполнено вне зависимости от того выполняется ли поиск в одном запросе или используется поиск по реквизитам справочника в цикле. Но в моём случае и справочник и прайс содержат десятки тысяч позиций. Всё бы ничего, но уж очень медленно получается при поиске соответствий Номенклатуры по полному наименованию.

Постановка задачи: найти элементы справочника Номенклатура, полное наименование которых совпадает с наименованием в прайсе поставщика. При больших объемах данных решение напрашивается само собой - использовать запрос.

Не буду долго рассуждать о поиске варианта решения. Сразу покажу запрос, который показал себя наиболее эффективным. ТаблицаДляПоиска это таблица значений, в которой 1 колонка заполненная значениями, загруженными из прайса.

Запрос = Новый Запрос(
   
"ВЫБРАТЬ
    |   ПОДСТРОКА(ТаблицаДляПоиска.НоменклатураXLS, 1, 40) КАК НоменклатураXLS_Индекс,
    |   ТаблицаДляПоиска.НоменклатураXLS КАК НоменклатураXLS
    |ПОМЕСТИТЬ ТаблицаДляПоиска
    |ИЗ
    |   &ТаблицаДляПоиска КАК ТаблицаДляПоиска
    |
    |ИНДЕКСИРОВАТЬ ПО
    |   НоменклатураXLS_Индекс
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |   СправочникНоменклатура.Ссылка КАК Номенклатура,
    |   СправочникНоменклатура.НаименованиеПолное КАК НоменклатураНаименование
    |ИЗ
    |   Справочник.Номенклатура КАК СправочникНоменклатура
    |       ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТаблицаДляПоиска КАК ТаблицаДляПоиска
    |       ПО ПОДСТРОКА(СправочникНоменклатура.НаименованиеПолное, 1, 40) = ТаблицаДляПоиска.НоменклатураXLS_Индекс
    |           И ПОДСТРОКА(СправочникНоменклатура.НаименованиеПолное, 1, 1000) = ТаблицаДляПоиска.НоменклатураXLS
    |ГДЕ
    |   СправочникНоменклатура.ЭтоГруппа = ЛОЖЬ
    |   И СправочникНоменклатура.Услуга = ЛОЖЬ"
);

Запрос.УстановитьПараметр("ТаблицаДляПоиска", ТаблицаДляПоиска);
РезультатЗапроса = Запрос.Выполнить();

Решение лежало на поверхности. Правда?

Вернуться к оглавлению... 


Про пакетные запросы. Индексы во временных таблицах

Сегодня с утра была пятница. Пришло время открыть великую тайну-у-у-у.

В пакетных запросах в качестве источника данных часто выступает временная таблица. У временной таблицы есть возможность создавать индексы. В каких случаях создание индекса может ускорить выполнение запроса, а в каких наоборот?

Начнем с того, что посмотрим, когда не нужно создавать индексы. Ведь на создание индекса тратится время и ресурсы. Если индекс не будет использоваться, то его создание только замедлит выполнение запроса. Нет смысла создавать индексы, если временная таблица очень маленькая. Нет смысла создавать индексы, если временная таблица соединяется с другой таблицей по полям, которые во второй таблице уже проиндексированы.

Так когда же имеет смысл создавать индексы? Оказывается всё очень просто. Индексы имеет смысл создавать в случае, если выполняется условие сравнения на равенство. В качестве примера можно посмотреть запрос в предыдущем пункте Заметочек. Там как раз используется индекс именно в подобной ситуации.

Возможно со временем индексы будут использоваться и при других вариантах сравнения. Поживем, увидим.

Вернуться к оглавлению...


Про СКД и запросы с итогами

В комментариях к публикациям Как выгрузить итоги запроса в одну колонку ? и Запросики для восьмерочки развернулась настоящая битва между Ish_2 и tango. Просто жуть какая-то. Но вопросы были подняты очень интересные. Я очень внимательно следил за ходом обсуждения и после очередного комментария с примером обработки от Ish_2, появилась обработка, которая демонстрирует построение многоуровнего дерева в одной колонке "Поле4" с использованием как запроса с итогами, так и СКД. За основу была взята обработка, приложенная к комментарию.

 

Ах, да. "В чем же фишка?" - спросите вы. Всё просто. Из СКД сложное многоуровневое дерево в дерево значений выгружается быстрее. На контрольном примере разница составила в 30 раз. При использовании запроса сам запрос выполняется сравнительно быстро, а вот скорость выгрузки результата запроса в дерево значений оставляет желать лучшего.

Так как программного кода как такового при использовании СДК нет, то не совсем очевиден способ реализации. Куда смотреть? Смотреть нужно в пользовательских полях. 

 

Собственно весь вывод данных в обработке при использовании СКД построен на пользовательских полях. Это сделано для того, чтобы сохранить нужную последовательность колонок в дереве значений. Если порядок следования реквизитов не важен или реквизиты не нужны в результирующем дереве значений, то и добавлять реквизиты в пользовательские поля не нужно.
Скачать Пример 8...

Но как вы, наверное, догадываетесь, "Пример 8" это не единственный вариант реализации многоуровневого дерева в одной колонке с использованием СКД. Поэтому был добавлен "Пример 9", в котором "Поле4" строится не через пользовательские поля, а через ресурсы. Чем он лучше варианта в "Пример 8"? Работает немного быстрее предыдущего примера и названия колонок в результирующем дереве значений получаются более "ожидаемые".

Особенностью реализации "Пример 9" является расположение ресурсов в группировках. Это сделано только для того, чтобы управлять порядком следования колонок в результирующем дереве значений. Иначе колонки с группировками будут расположены впереди, а уже за ними колонка "Поле4". Чтобы можно было управлять порядком расположения реквизитов необходимо вначале сформировать группировки по реквизитам, а затем реквизиты описать как ресурсы. При необходимости формирования определенного порядка следования колонок в результирующем дереве необходимо для некоторых группировок заменить состав выбранных полей с Авто на требуемый. Если порядок следования реквизитов не важен или реквизиты не нужны в результирующем дереве значений, то и добавлять реквизиты в ресурсы не нужно.
Скачать Пример 9...

Возможность выбора варианта реализации многоуровнего дерева в одной колонке дерева значений есть. В данной публикации приведено 4 способа. Выбирайте. Реализуйте.

Вернуться к оглавлению...


Про дерево значений

Уже были рассмотрены примеры заполнения дерева значений с использованием запроса и СКД. Сейчас предлагаю рассмотреть несколько иной вариант работы с деревом значений.

Краткое описание исходных условий для этого варианта. Работаем с деревом значений имеющим 2 уровня. Для первоначального отображения формируется только первый уровень строк дерева и добавляется по одной пустой строке на втором уровне для отображения плюсиков возле строк. Первый уровень свернут. Далее, при разворачивании пользователем строки первого уровня, пустая строка второго уровня заменяется на необходимый набор данных. Необходимый набор данных получаем, например, запросом в виде таблицы значений.

Что мы получаем при использовании такого варианта работы с деревом? Быстрое первоначальное отображение дерева для пользователя. Что ещё? Немного больше кода при работе с деревом.

Вот тут мы и попляшем немного вокруг вопроса: "Как поместить необходимый набор данных в строки второго уровня?" Есть варианты.

Наиболее очевидный вариант описан в начале этой статьи в части "Про циклы в одну строку". Но он не единственный. Предлагаю рассмотреть ещё один кусочек кода, который намного производительнее при большом количестве строк в необходимом наборе данных.

Процедура ДеревоЗначенийПередРазворачиванием(Элемент, СтрокаДереваЗначений, Отказ)

    Если
СтрокаДереваЗначений.УровеньРазвернут Тогда
        Возврат;
    КонецЕсли;

   
СтрокиГруппировки = СтрокаДереваЗначений.Строки;
   
СтрокиГруппировки.Очистить();

   
ТаблицаЗначений = ПолучитьНаборНеобходимыхДанных(СтрокаДереваЗначений);

    Если
ТаблицаЗначений.Колонки.Количество() * 2 > ТаблицаЗначений.Количество() Тогда
        Для каждого
СтрокаТаблицыЗначений Из ТаблицаЗначений Цикл
           
ЗаполнитьЗначенияСвойств(СтрокиГруппировки.Добавить(), СтрокаТаблицыЗначений);
        КонецЦикла;
    Иначе
        Для
Индекс = 1 По ТаблицаЗначений.Количество() Цикл
           
СтрокиГруппировки.Добавить();
        КонецЦикла;

        Для каждого
Колонка Из ТаблицаЗначений.Колонки Цикл
           
СтрокиГруппировки.ЗагрузитьКолонку(ТаблицаЗначений.ВыгрузитьКолонку(Колонка.Имя), Колонка.Имя);
        КонецЦикла;
    КонецЕсли;

   
СтрокаДереваЗначений.УровеньРазвернут = Истина;

КонецПроцедуры
// ДеревоЗначенийПередРазворачиванием()

Циклы также можно оформить в одну строку, но для сохранения читаемости кода этого не сделано. На контрольном примере предложенный вариант заполнения был производительнее в 4 раза. Конечно же всё зависит от исходных данных и на других данных результаты могут быть другие, но о том, что 1С всё таки интерпретатор не стоит забывать. Правило "Чем меньше команд, тем быстрее работает программа" остается актуальным и по сей день.

Скачать пример...
Ещё про дерево значений можно посмотреть здесь...

Вернуться к оглавлению...


Про таблицу значений

Увидел публикацию Преобразование ТаблицыЗначений во Временную таблицу автора sashapere, в которой ТаблицаЗначений с колонками неопределенного типа подготавливается для использования в запросах. Т.е. проверяются типы значений в колонках, а затем создается новая таблица значений с колонками нужного типа и данные переносятся в неё. Такую таблицу значений уже можно использовать в запросах, передавая её в качестве параметра или источника данных для ПостроителяЗапросов и ПостроителяОтчетов.

Мне показалось, что код не очень эффективен и это можно сделать быстрее. Вот что из этого получилось.

КолонкиТаблицыЗначений = ТаблицаЗначений.Колонки;
Для
Индекс = 0 По КолонкиТаблицыЗначений.Количество() - 1 Цикл
   
МассивЗначений = ТаблицаЗначений.ВыгрузитьКолонку(0);

   
// Получаем типы значений, которые используются в колонке
   
Соответствие = Новый Соответствие;
   
СтТипЗначения = ТипЗнч(Неопределено);
    Для каждого
Значение Из МассивЗначений Цикл
       
ТипЗначения = ТипЗнч(Значение);
        Если
СтТипЗначения <> ТипЗначения Тогда
           
СтТипЗначения = ТипЗначения;
           
Соответствие.Вставить(ТипЗначения);
        КонецЕсли;
    КонецЦикла;

   
// Преобразуем соответствие в массив типов значений
   
МассивТипов = Новый Массив;
    Для каждого
КлючИЗначение Из Соответствие Цикл
       
МассивТипов.Добавить(КлючИЗначение.Ключ);
    КонецЦикла;

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

Допускаю, что и этот код тоже можно оптимизировать. Нет предела совершенству. Поэтому предлагаю сравнить с другими вариантами в "Примере 10". Авторы двух добавленных вариантов sashapere и i132.

Скачать Пример 10...

Вернуться к оглавлению...


Про работу с COMОбъект("V81.Application") или как разогнать 1С в 1000 раз

Очень интересная публикация OLE - монитор автора ghostishe, в которой приложена обработка COM MONITOR. Мне как раз необходимо было сверить справочники в двух базах данных. В предложенной обработке всё понятно, но скорость получения данных из подключенной базы мне показалась крайне низкой. После небольшого эксперимента удалось получить такие же данные как в этой обработке, только в 30 раз быстрее, а после небольшой модификации удалось поднять скорость получения данных из подключенной базы ещё в 5 раз. Добавил "Пример 6". В предлагаемом примере разница во времени выполнения по сравнению с исходным образцом может составить от 15 до 1500 раз - это зависит от состояния базы данных и от объема получаемых данных. Чем больше данных нужно получить, тем больше может получиться разница.

Итак, что и как сравниваем. Во вложении 2 обработки: COM MONITOR и Пример 6 для COM Monitor.

COM MONITOR - во вложении, это почти оригинальная обработка, в которую добавлены команды для выполнения замера времени получения данных из подключенной базы. COM MONITOR работает в двух режимах: с закрытым окном подключенной базы данных и с открытым. Т.к. с открытым окном обработка работает очень медленно, то для сравнения берем только замер с закрытым окном.

Пример 6 для COM Monitor - эта обработка построена на основе COM MONITOR, ну, или почти так. Во всяком случае основной функционал (идею) постарался сохранить. Пример 6 для COM Monitor работает в двух режимах: с использованием дополнительной обработки и без неё. При установке соответствующего флажка используется дополнительная внешняя обработка, которая запускается в подключенной базе данных. Данные внешней обработке передаются через COMSafeArray, который в дальнейшем и обрабатывается. Обратно данные передаются аналогичным образом. Ни каких внешних компонент, всё по честному. AutoIt используется только чтобы вернуть фокус в 1С:Предприятие, а WScript для замера времени выполнения.

Скачать COM MONITOR от ghostishe...
Скачать Пример 6 для COM Monitor...

А теперь главный вопрос: за счет чего получается столь значительное ускорение? Ответ прост: за счет снижения количества разыменований. Да, да. На такой пустяковой операции как разыменование можно добиться столь значительного ускорения. Чем меньше точек в тексте модуля, тем выше скорость его выполнения. Разница особенно заметна при использовании COMОбъект(). Т. к. кроме разыменования здесь немаловажную роль играет передача данных между приложениями, то именно этот момент и решает применение дополнительной обработки. Данные между приложениями передаются всего 2 раза: туда и обратно.

Запускайте, тестируйте, удивляйтесь. Smile

Вернуться к оглавлению...


Про работу с НастройкаПериода, ЗаполнитьЗначенияСвойств и вообще

Вводные данные, ну, или описание исходной задачи были следующие:

  • Есть форма Основная, в которой есть возможность настраивать период. Для настройки периода используется объект НастройкаПериода, который вызывается на редактирование по кнопке.
  • Также ещё есть форма Настройка, в которой также можно редактировать период, но не только через объект НастройкаПериода, а ещё и через поля ввода дат начала и окончания периода.
  • Необходимо чтобы настройки указанные в форме Настройка можно принять и перенести в форму Основная или отказаться от сделанных изменений.

Казалось бы, всё просто, нужно в форме Настройка создать ещё один объект НастройкаПериода и заполнить его свойства. Например, так:

Функция СкопироватьНустройкуПериода(НастройкаПериодаИсходный)
   
НастройкаПериодаРезультат = Новый НастройкаПериода;
   
ЗаполнитьЗначенияСвойств(НастройкаПериодаРезультат, НастройкаПериодаИсходный);
    Возврат
НастройкаПериодаРезультат;
КонецФункции

Вот тут и начинается самое интересное. При использовании команды ЗаполнитьЗначенияСвойств свойства объекта НастройкаПериодаРезультат заполняются неверно, т.е. свойства, конечно, заполняются, но не так как в исходном объекте. А в некоторых случаях вообще возникает ошибка.

Почему нельзя просто присвоить? НастройкаПериодаРезультат = НастройкаПериодаИсходный; Потому, что получится не новый объект, а ссылка на исходный объект.

Один из вариантов создания нового объекта НастройкаПериода может быть таким:

Функция СкопироватьНустройкуПериода(НастройкаПериодаИсходный)
    Возврат
ЗначениеИзСтрокиВнутр(ЗначениеВСтрокуВнутр(НастройкаПериодаИсходный));
КонецФункции

С этим разобрались и новый объект НастройкаПериода у нас есть - можно редактировать. Теперь в случае отказа можно просто ничего не делать. Закрыть форму Настройка и всё.

Теперь рассмотрим сохранение (перенос) измененных данных периода в основную форму. Если редактирование периода было выполнено через объект НастройкаПериода, то всё просто.

НастройкаПериодаИсходный = НастройкаПериодаРезультат;

А вот в случае редактирования дат периода не всё так однозначно. Потому что способ, который используется в типовых конфигурациях, в некоторых случаях опять же дает неожиданный результат. Т.е. иногда срабатывает, а иногда нет. Вот код с заплаткой.

НастройкаПериодаИсходный = НастройкаПериодаРезультат;

Если
ДатаНачала <> НастройкаПериодаИсходный.ПолучитьДатуНачала()
    или
ДатаОкончания <> НастройкаПериодаИсходный.ПолучитьДатуОкончания() Тогда
   
НастройкаПериодаИсходный.УстановитьПериод(ДатаНачала, ?(ДатаОкончания = '00010101', ДатаОкончания, КонецДня(ДатаОкончания)));

   
// Заплатка
   
Если ДатаНачала <> НастройкаПериодаИсходный.ПолучитьДатуНачала()
        или
ДатаОкончания <> НастройкаПериодаИсходный.ПолучитьДатуОкончания() Тогда
       
НастройкаПериодаИсходный = Новый НастройкаПериода;
       
НастройкаПериодаИсходный.ВариантНачала = ВариантГраницыИнтервала.КонкретнаяДата;
       
НастройкаПериодаИсходный.ВариантОкончания = ВариантГраницыИнтервала.КонкретнаяДата;
       
НастройкаПериодаИсходный.ДатаНачала = ДатаНачала;
       
НастройкаПериодаИсходный.ДатаОкончания = ДатаОкончания;
    КонецЕсли;
КонецЕсли;

Как видно из кода, заплатка в качестве периода устанавливает ПроизвольныйПериод. Ах, да. Не видно. Но всё равно в качестве периода устанавливается ПроизвольныйПериод.

Я прекрасно понимаю, что здесь рассмотрен некоторый частный случай, который в типовых конфигурациях не встречается. Но. Есть ли что-то особенное в постановке задачи? По моему нет. Так почему же такой подход не используется в типовых конфигурациях? Не связано ли это с тем, что разработчики типовых конфигураций фирмы 1С не смогли победить объект НастройкаПериода. Smile

В качестве примера приведу "Универсальный отчет", в котором также есть как Основная форма, так и форма Настройки. При этом если изменить период в форме Настройки, он тут же изменяется и в Основной форме. Т.е. закрыв форму Настройки можно отказаться от всех сделанных изменений кроме изменений периода. Вот такие пироги.

Скачать пример...

Вернуться к оглавлению...


Про итоги в регистрах накопления

Пришло время испытать публикацию MMF на довольно большой базе данных. Обнаружился очень интересный факт. Таблица итогов по регистру остатков ЗаказыПокупателей была больше таблицы самого регистра в 50 раз и составляла 20% от всей базы УПП. Все попытки побороть это явление "цивилизованными" способами привели к уменьшению таблицы итогов лишь в 2.5 раза, при этом таблица самого регистра накопления выросла в 2 раза. Тогда было принято решение отключить расчет итогов по этому регистру. На производительности и функциональности это ни как не сказалось, а вот на размерах базы данных и на размерах архивных копий отразилось самым положительным образом.

Т.к. через интерфейс это сделать не получилось, то вот, собственно, код:

РегистрыНакопления.ЗаказыПокупателей.УстановитьПериодРассчитанныхИтогов('00010101');

С методической точки зрения, возможно, это не самое лучшее решение. Но меня поразила его эффективность и простота.

Скачать пример...

Для просмотра внутренней структуры файловой базы данных 1С:Предприятия 8 предлагаю обратить внимание на Tool_1CD.

Вернуться к оглавлению...


Про танцы с бубном

Пришло время разучить новый танец. Ни когда раньше такого не делал, но вот пришлось.

Что есть? Конфигурация на базе типового решения 1С:Бухгалтерия предприятия 8 (2.0.31.36) - Учет в МФО (релиз 2.0.31.36), разработчик Фирма "Альянс-Информ". База работает на платформе 8.2.13.219.

Что хотим? Перейти на платформу 8.2.15.294.

Казалось бы, что ничего сложного нет. Установить платформу, запустить базу, сконвертировать базу при запуске и работать в своё удовольствие. Но не тут то было. После конвертации база почему-то начинает падать при запуске на любой версии платформы, начиная с 8.2.14.519. При этом на 8.2.13.219 всё работало как в режиме Конфигуратор, так и в режиме 1С:Предприятие.

Восстанавливаем архив, лезем в конфигуратор и видим, что конфигурация на поддержке без возможности изменения, т.е. типовая. Нужно что-то делать. Но что? Тестирование/исправление, реструктуризация, выгрузка/загрузка - все ранее применявшиеся движения шаманского танца не помогли. После конвертации база падает при запуске.

Что дальше? Разучим новые движения незамысловатого шаманского танца. Начинаем сначала. Заходим в конфигуратор платформы 8.2.13.219 пустой базы. Восстанавливаем архив базы данных из DT-файла. Сохраняем конфигурацию в CF-файл в меню Конфигурация - Сохранить конфигурацию в файл. Включаем возможность изменения в меню Конфигурация - Поддержка - Настройка поддержки. Обновляем конфигурацию базы данных (F7) или в меню Конфигурация - Обновить конфигурацию базы данных. Выходим из конфигуратора. Заходим в конфигуратор платформы 8.2.15.294. Выбираем ту же базу. Соглашаемся с предложением сконвертировать базу данных. Загружаем выгруженный ранее CF-файл в меню Конфигурация - Загрузить конфигурацию из файла. Обновляем конфигурацию базы данных (F7) или в меню Конфигурация - Обновить конфигурацию базы данных. Вот собственно и всё. Получаем работающую базу под платформой 8.2.15.294 с типовой конфигурацией на поддержке без возможности изменения. Т.е. всё то, что и хотелось получить первоначально.

Вывод. В арсенале настоящего шамана может быть много разных танцев, но архивную копию делать нужно.

Вернуться к оглавлению...


Про использованные материалы

При подготовке статьи использованы также материалы других авторов. Если вам понравились их обработки, то можете поставить плюсик на их публикациях. Думаю, что они не будут против. Все ссылки есть в статье.

Вернуться к оглавлению...


Про Разукрашку

Для раскрашивания текстов модулей в статье была использована Разукрашка.
Пользуйтесь Разукрашкой для раскрашивания кода и запросов 1С:Предприятия, а также кода Delphi. Smile
Прошу воспринимать это не как рекламу, а как добрый совет для авторов других публикаций.

Вернуться к оглавлению...


Последний штрих

Идя навстречу пожеланиям читателей, фиксирую изменения в различных редакциях публикации.

07.09.2010. Добавил в заметочки "Про получение строки пробелов длиной 10000 символов"

12.10.2010. Добавил в заметочки "Про работу с COMОбъект("V81.Application") или как разогнать 1С в 1000 раз

12.01.2011. Добавил в заметочки "Про СКД и запросы с итогами" и два примера реализации многоуровнего дерева значений в одной колонке с помошью СКД

03.08.2011. Добавил в заметочки "Про дерево значений"

29.08.2011. Добавил в заметочки "Про типы данных. Расчет сумм по выделенным ячейкам табличного поля". Обновил Пример3_2.epf. Теперь Гостинец.epf "отдыхает"

05.10.2011. Добавил в заметочки "Про типы данных. Динамическая настройка колонок табличного поля"

12.10.2011. Добавил в заметочки к разделу "Про циклы в одну строку" обработку для формарования программного кода в одну строку.

13.10.2011. Добавил в заметочки "Про итоги в регистрах накопления"

17.11.2011. Добавил про разбор длинных строк в массив с возможностью предварительной обработки данных. Обновил Пример 7.

19.01.2012. Добавил в заметочки "Про работу с НастройкаПериода, ЗаполнитьЗначенияСвойств и вообще"

31.01.2012. Добавил в заметочки "Про танцы с бубном"

09.03.2012. Добавил в заметочки "Про хитрые запросы. Тэта-соединения 3. Строки неограниченной длины"

23.03.2012. Добавил в заметочки "Про пакетные запросы. Индексы во временных таблицах"

22.06.2012. Добавил в заметочки "Про таблицу значений"

Вернуться к оглавлению...

 

01.06.2010 /Константинов Алексей Викторович/
Редакция от 22.06.2012

Group 2087328267.png

См. также

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    7499    bayselonarrend    20    

154

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    5962    dsdred    16    

80

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    17783    YA_418728146    26    

71

Механизмы платформы 1С Программист Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    23783    SeiOkami    48    

135

WEB-интеграция Универсальные функции Механизмы платформы 1С Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    14772    YA_418728146    7    

166
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Evg-Lylyk 4842 01.06.10 14:39 Сейчас в теме
Так программный код выполняется значительно быстрее. Всё дело в переходах между командами.

И на сколько быстрее? (примерчик)
dragonbridge; +1 Ответить
2. alexk-is 6544 01.06.10 14:58 Сейчас в теме
(1) Количество повторов 1000000
Замер код записан в 4 строки. Завершено за 3,329 сек.
Замер код записан в 1 строку. Завершено за 0,5 сек.

У меня получилось приблизительно в 6 раз. Но здесь нужно учитывать только время переходов. Если в цикле будут команды, которые выполняются медленно, то и результаты будут иными.
3. alexk-is 6544 01.06.10 15:06 Сейчас в теме
4. awa 2610 01.06.10 15:14 Сейчас в теме
(1)(2) Я думаю, что разница будет только в режиме отладки. В обычном режиме разницы быть не должно.
6. alexk-is 6544 01.06.10 15:39 Сейчас в теме
(4) Эх... раскусил... Да, действительно был включен режим отладки. Переделал тест. Теперь результат такой.

Замер код записан в 6 строк. Завершено за 1,532 сек.
Замер код записан в 1 строку. Завершено за 0,859 сек.

Почти в 2 раза. Тоже не плохо.
12. alexk-is 6544 01.06.10 16:06 Сейчас в теме
(4) Приложенный тест убедил?
16. awa 2610 01.06.10 17:27 Сейчас в теме
(12)(15) Да, убедил. Это действительно сказываются дополнительные коды (1) в компилированном коде, которые означают номер строки для отладки. В 1С, в отличие от нормальных сред программирования (типа Visual Studio или Embarcadero RAD) нет разделения на режимы компиляции Debug и Release. В 1С, по сути, всегда режим Debug. Ради интереса я перенес тест из формы в модуль обработки, поставил на нее пароль, и обфусцировал ее. Обфускация, кроме всего прочего, выкидывает отладочные коды (1). И результаты сразу стали одинаковыми! Правда, чуть больше, чем не для обфусцированных - вместо 1 сек для 1 строки и 1,4 сек для 6 строк стало по 2 сек. для обоих вариантов, что вполне объяснимо - обфускация добавляет лишние переходы и прочие запутывающие коды.
Но, по большому счету, и раньше было известно, что 1С для всяких сильно вычислительных и переборных задач совсем не подходит. В реальной же жизни, как правило, скорость работы 1С упирается в скорость работы с БД, и на этом фоне оптимизация просто кода 1С приносит практически незаметные результаты.
HystriX; admin; MariusUrsus; talych; Evil Beaver; tormozit; waol; JohnyDeath; zqzq; krv2k; karantella; AleksR; Sol; BabySG; alexk-is; Stety; СергейКа; Anything; Artem N; Шёпот теней; +20 Ответить
17. alexk-is 6544 01.06.10 17:56 Сейчас в теме
(16) Не совсем так. После получения данных из базы наступает момент, когда её необходимо показать пользователю. Вот тут-то и наступает самый интересный момент. Сколько будет стоить поднять производительнось пользовательского ПК, например, на 20% ? А тут халява :)
452. HystriX 20.12.18 08:42 Сейчас в теме
(16) Возможно, отсутствие разделения на Debug и Release обусловлено тем, что в 1С есть возможность для удобства помощи пользователям и разбора всяких нестандартных ситуаций прямо в открытом сеансе установить флаг "Отладка в текущем сеансе разрешена" и сразу же подключиться конфигуратором и начать отладку. И эта возможность иногда оправдывает себя намного больше, чем едва ощутимый прирост производительности алгоритмов :)
Мах; user1135262; +2 Ответить
320. пользователь 20.12.11 14:14
Сообщение было скрыто модератором.
...
5. Diversus 2329 01.06.10 15:19 Сейчас в теме
Для каждого СтрокаТЗ Из Таблица1 Цикл ЗаполнитьЗначенияСвойств(Таблица2.Добавить(), СтрокаТЗ) КонецЦикла;


А вот так работает, медленней?
Таблица2 = Таблица1.Скопировать();

Или я чего то не понял?
7. alexk-is 6544 01.06.10 15:41 Сейчас в теме
(5) Я имел ввиду вариант Таблица = Таблица1 + Таблица2 + Таблица3 + ... ТаблицаN
8. e.kogan 1895 01.06.10 15:42 Сейчас в теме
Вот за заход с итоговыми полями в запросе большое спасибо, раньше не встречала.
9. alexk-is 6544 01.06.10 15:53 Сейчас в теме
(8) Почему не встречала? В http://www.infostart.ru/public/69707/ встречается 4 раза, а эта публикация висит на главной уже больше месяца.

Посмотри её. Там ещё много вкусного :)
10. e.kogan 1895 01.06.10 15:54 Сейчас в теме
(9) Потому что туда в код не залезала, времени не было.
11. alexk-is 6544 01.06.10 16:02 Сейчас в теме
(8) Ну, хоть кого-то удивил.
13. anig99 2852 01.06.10 16:38 Сейчас в теме
хммммм...очень похоже всё-таки на баг компилятора...Скорость работы программы НЕ ДОЛЖНА зависеть от таких вещей...
Душелов; Шёпот теней; +2 Ответить
22. WKBAPKA 215 02.06.10 08:37 Сейчас в теме
2(13): вот и я о том подумал, на самом деле, одна строка или 6 строк, машине (компилятору) по барабану, для нее на вход поступает линейный поток символов (включая управляющие символы). И какая тут разница, сколько строк или пробелов? Это разве что, время разбора лексем увеличивается за счет работы со строками, типа, чем больше пробелов и прочих не значащих символов, тем больше время разбора, но что бы в два раза!!!
14. ildarovich 7930 01.06.10 16:43 Сейчас в теме
С результатами согласен
Функция ТочноеВремя() 
	
	Script = Новый COMОбъект("MSScriptControl.ScriptControl");
	Script.Language = "javascript"; 
	Возврат Script.eval("new Date().getTime()"); 
	
КонецФункции

Процедура КнопкаСформироватьНажатие(Кнопка)
	
	Старт = ТочноеВремя();
	
	А = 0;
	Для Сч = 1 По 1000000 Цикл
		А = А + 1;
	КонецЦикла;
	
	Сообщить("В несколько строк:" + (ТочноеВремя() - Старт) + " мск");
	
	Старт = ТочноеВремя();
	
	А = 0;Для Сч = 1 По 1000000 Цикл А = А + 1;КонецЦикла;
	
	Сообщить("В одну строку:" + (ТочноеВремя() - Старт) + " мск");
	
КонецПроцедуры
Показать

Результат(вне отладки):
В несколько строк:1 531 мск
В одну строку:1 078 мск

Но я бы объяснил это не лишними повторениями или переходами между командами, а наличием возможных точек останова и возможностью указания строки ошибки.
Stety; Anything; Шёпот теней; +3 Ответить
15. alexk-is 6544 01.06.10 16:56 Сейчас в теме
(14) Не вижу принципиальной разницы. Давай назовем так - Переход между командами с созданием возможных точек останова и возможностью указания строки ошибки. Результаты тестов от этого не изменятся.
18. Abadonna 3968 01.06.10 19:46 Сейчас в теме
Что-то мне кажется, что говорить в контексте 1С "скомпилированный" не совсем корректно. 1С таки интерпретатор, имхо.
19. awa 2610 01.06.10 20:44 Сейчас в теме
(18) На самом деле 1С и компилятор и интерпретатор одновременно. Исходный код компилируется в промежуточный "п-код" либо в момент первого обращения к модулю, если исходный текст модуля открыт, либо заранее, если исходный текст модуля запаролен или исходный текст модуля отсутствует. Далее полученный "п-код" выполняется виртуальной машиной 1С в режиме интерпретатора.
Правда, не знаю, как выполняется клиентский код в тонком и веб-клиентах 8.2.

(17) Ну давай посчитаем. В твоем тесте цикл выполняется миллион раз, в варианте шести строк внутри цикла 4 строки, т.е. за время выполнения теста происходит обработка отладочного кода (1) четыре миллиона раз. Именно этих четырех миллионов вызвовов команды (1) нет в варианте с одной строкой. Уходит на это примерно пол-секунды (на моем рабочем компе разница между тестами 0.4 секунды). В обычной жизни для вывода пользователю результатов запроса из БД надо выполнить не более нескольких тысяч строк (с учетом всех циклов), что на три порядка меньше, чем в тесте. Т.е. способом "пишем всю программу в одну строку" ты будешь ловить миллисекунды.
Я отнюдь не отрицаю, что эффект есть, я просто говорю, что, как правило, он совсем не стоит внимания. Возможно, в исключительных случаях, и бывает, что таким способом можно получить хоть немного заметную экономию времени. Но скорее всего, это тяжелые алгоритмические или переборные задачи, которые, в таком уж случае, гораздо эффективнее писать на других, компилируемых, языках. С++, например. Выигрыш по времени выполнения чисто алгоритмической программы на С++ по сравнению с 1С может достигать нескольких тысяч раз.
HystriX; WarAn; a0212; pvlunegov; Mingrel; Evil Beaver; awk; Artem N; +8 Ответить
24. anig99 2852 02.06.10 08:55 Сейчас в теме
(19) к тому же множество выкладок по оптимизации кода идет в сторону сокращения циклов или полного их устранения за счет запросов/переноса на сервер...
20. anig99 2852 01.06.10 21:10 Сейчас в теме
а если запоролить обработку?
21. WKBAPKA 215 02.06.10 08:34 Сейчас в теме
а про циклы мне не совсем понятно... вернее понятно :o , но почему так?
23. WKBAPKA 215 02.06.10 08:40 Сейчас в теме
прочитал последние посты, вопросы отпали... :)
25. awa 2610 02.06.10 10:01 Сейчас в теме
Кстати, в приведенном коде разбора строки с элементами в массив, есть ошибка, а точнее ограничение. Если в элементах разбираемой строки встречается двойная кавычка, то приведенный код упадет. Поэтому перед преобразованием надо добавить
РазбираемаяСтрока = СтрЗаменить(РазбираемаяСтрока, """", """""");
alexk-is; +1 Ответить
27. alexk-is 6544 02.06.10 10:36 Сейчас в теме
(25) Ни каких ограничений нет. См. пост (25) - там смимаются все ограничения. :)

А если серьезно, то у меня такой способ разбора строк встречается часто. Взял из модуля, где разбираются строки вида ЭлементыФормы.КоманднаяПанель.Кнопки.Подменю.Кнопки.Действие.Подсказка

Главное ведь сам прицип. Если принцип понятен, то модифицировать команду под разбор, например, строки чисел уже не составит труда.

(Подсказка: S заменить на N и убрать некоторые кавычки)
26. WellMaster 104 02.06.10 10:32 Сейчас в теме
Иногда встречал простые задачи, которые нельзя ни перенести на сервер, ни реализовать на запросах - все делалось на клиенте.
Вот мои замеры (10 млн итераций):

Замер код записан в 6 строк. Завершено за 25,652 сек.
Замер код записан в 1 строку. Завершено за 14,771 сек.

11 секунд выигрыша в моем случае - большой плюс.
Предложенный способ оптимизации действительно отношу к особенностям компилятора/интерпритатора, а не к оптимизации кода в полном смысле этого слова.
Но все равно плюс автору за статью.
28. Ish_2 1112 02.06.10 13:08 Сейчас в теме
1. Почему для построения двухуровневого дерева нельзя обойтись только первой частью запроса ?

2. Зачем в одной колонке нужно иметь разные типы ?

3. Не понял текста запроса после "Объединить Все" .
- Второй запрос будет пустым . зачем это нужно ?
4.
"ИТОГИ
| Организация КАК СтруктураДоговоров,
| СУММА(Сумма)
|ПО
| Организация");"

- После опции ИТОГИ употреблена не агрегатная функция , а "Организация" .
Что это ?
29. Ish_2 1112 02.06.10 13:15 Сейчас в теме
30. alexk-is 6544 02.06.10 19:01 Сейчас в теме
(29) Вот пока выложил только скриншот "Пример 3". Как думаешь, это будет интересно?
В двух словах - там по периодическому регистру сведений КурсыВалют вычисляются периоды действия курсов и ещё ряд показателей, при этом исключаются записи в которых курс установлен такой же как в предыдущей записи.
31. Ish_2 1112 02.06.10 19:19 Сейчас в теме
(31) Пока замечание.
Оформлял бы запросы с помощью временных таблиц. И надежнее в выполнении и нагляднее. Уж сколько говорено на эту тему ...
И 1с рекомендует обходиться без вложенных запросов.
34. alexk-is 6544 02.06.10 21:55 Сейчас в теме
(31) Переделал на пакетный запрос.
Однако вопрос в (30) был не про "Пример 2", а про "Пример 3".
32. Ish_2 1112 02.06.10 19:27 Сейчас в теме
Кстати , по пред.сообщению . А я получал такие двухуровневые деревья в "лоб", т.е. в цикле прокручивал выборку и заполнял каждую строку дерева. Твой способ ,насколько я понимаю, побыстрее и поизящнее.

33. alexk-is 6544 02.06.10 20:07 Сейчас в теме
(32) Ну, да. Иначе зачем огород городить?
35. Поручик 4692 02.06.10 23:01 Сейчас в теме
Покажи пример. Интересно. Я так понял, на нём можно построить что-то таблицы изменения задолженности.

Фичу с контрагентами будет время воткну в конфу.
36. alexk-is 6544 02.06.10 23:40 Сейчас в теме
(35) Изменение задолженности? Разве типовые отчеты этого не показывают? Хотя остатки в разрезе документов можно таким образом развернуть.

Нет. Я имел ввиду несколько иное представление именно периодических регистров сведений: КурсыВалют, ЦеныНоменклатуры и т.д. Где это может использоваться? Например, здесь http://infostart.ru/public/70802/
37. alexk-is 6544 03.06.10 12:40 Сейчас в теме
Добавил про сворачивание массивов.
38. Ish_2 1112 04.06.10 10:42 Сейчас в теме
Для ,в целом симпатичного, примера 3 нужно указать , что в случае большой таблицы регистра КурсыВалют (более 1000 записей), мы получим серьезное замедление.
Дело , конечно, в том , что при соединении по неравенству в первом запросе размер "промежуточной" таблицы запроса резко возрастает.

Например , получение первой временной таблицы Периоды при помощи кодинга может дать многократный выигрыш по быстродействию .



Шёпот теней; +1 Ответить
39. alexk-is 6544 04.06.10 11:18 Сейчас в теме
(38) По оптимизации выборки в нарастающих итогах могу дать ссылочку http://infostart.ru/public/61295/ :)

Здесь фишка в другом - убрать повторяющиеся данные из цепочки, а оставить только точки перехода с датами, когда данный переход был выполнен.
Т.е. для цепочки 0, 0, 1, 1, 1, 0, 0, 0, 1
должны остаться только 0, 1, 0, 1
Шёпот теней; +1 Ответить
40. Шёпот теней 1782 04.06.10 11:53 Сейчас в теме
(38) ... неужели ... не ужели ... НЕужели ... неУЖЕЛИ ... вотВЕДЬвот ...
42. Ish_2 1112 04.06.10 12:09 Сейчас в теме
(40) Да ,Шепот. Применение в запросе соединения по неравенству - "в лоб" ,
может дать плачевные результаты.
41. Ish_2 1112 04.06.10 12:06 Сейчас в теме
Второй в пакете запрос я еще не осилил - до твоей "фишки" не дошел.

Отметив возможное замедление , продолжим "ковырять" первый запрос пакета.
В нем фильтрация по &Валюта применена дважды , причем один раз в условии соединения. На мой взгляд , эффективнее и понятнее будет следующий запрос для получения временной таблицы "Соединения"

Выбрать РАЗРЕШЕННЫЕ КурсыВалют.Период
Поместить Периоды
из Регистр.КурсыВалют
Где КурсыВалют.Валюта=&Валюта;

ВЫБРАТЬ
Периоды.Период как Период1,
Максимум (ЕСТЬNULL(Периоды1.Период, Периоды.Период)) КАК Период2
Поместить Соединения
Из
Периоды КАК Периоды
Левое Соединение Периоды КАК Периоды1
Периоды.Период > Периоды1.Период
Сгруппировать по
Периоды.Период
44. alexk-is 6544 04.06.10 13:36 Сейчас в теме
(41) :)
- Как-то не очень получается...
- Конечно можно и получше нарисовать. Ну, там в трехмерной проекции...
- А я бы нарисовал немного в профиль
- Да потому, что у вас всё в профиль
© Миссия Клеопатра


Добавил вариант с оптимизацией. Работает немного побыстрее, но понять, что делается в двенадцати пакетном запросе мне кажется сложнее. :)
47. alexk-is 6544 04.06.10 14:30 Сейчас в теме
(41) Хочу скромно поинтересоваться по поводу "Пример 3 с оптимизацией"...
Ну, как?
43. Ish_2 1112 04.06.10 13:33 Сейчас в теме
Посмотрел второй запрос.
Пример 3 хорош лишь как любопытная демонстрация запросной техники , но ни в коем случае не образец решения задачи. Лучше бы явно это указать в теме.
Действительно , выгрузив таблицу регистра в таблицу значений мы за ОДИН проход получим выходное дерево многократно быстрее.
45. alexk-is 6544 04.06.10 13:43 Сейчас в теме
(43) Там не дерево. Там список.
46. anig99 2852 04.06.10 14:30 Сейчас в теме
а на том дереве... или плоды познания, или русалка, или вообще кот, который ссыт в тапки...
49. Ish_2 1112 04.06.10 14:38 Сейчас в теме
За (46) гони Сашу , он нас с сурьёзного настроя сбивает.
59. anig99 2852 04.06.10 15:45 Сейчас в теме
(49) пятница...жарко...вечером ещё ехать на шабашку... дай коту нассать в тапки...
48. Ish_2 1112 04.06.10 14:34 Сейчас в теме
Хм.. А как у тебя тема обновляется ?
Скромно поинтересуюсь : а можно посмотреть пример 3 - оба варианта до оптимизации и после.

Первый запрос не изменился. Во втором поля выборки, два внутренних соединения, Итоги - как были так и остались.
50. alexk-is 6544 04.06.10 14:47 Сейчас в теме
(48) Там ещё 1 файл. Теперь их 5. Должен быть пакет из 12 запросов
52. Ish_2 1112 04.06.10 15:04 Сейчас в теме
(50) Скачал .Посмотрел. Мда.. "Он уважать себя заставил" !
Ты не подумай - я тоже энтузиаст и всё такое...
Но увидев текст пакета оробел : стоило ли ?
53. alexk-is 6544 04.06.10 15:08 Сейчас в теме
(52) Что нам стоит дом построть - нарисуем будем жить! :)
Ну, так как?
60. Ish_2 1112 07.06.10 08:08 Сейчас в теме
(53) В субботу попробовал твой "Пример № 3"
Теперь и ты отведай моего гостинца .

1. Текст запроса сокращен в 1,5 раза.
2. Быстродействие запроса увеличилось в 1,5 раза

В прикрепл.файле "Гостинец" твоя обработка "пример № 3" с измененным текстом запроса.
Прикрепленные файлы:
Гостинец.epf
61. alexk-is 6544 07.06.10 10:12 Сейчас в теме
(60) Всё зависит от информационной базы. На SQL разницы не получилось, а вот на файловой "гостинец" на 18% быстрее. Только "гостинец" по первой дате выдает неправильный результат в "Изменение курса". Всё равно спасибо. Буду изучать.
62. Ish_2 1112 07.06.10 10:20 Сейчас в теме
(61) Проверялась в субботу действительно на файловом варианте.

На небольших объёмах проверять бессмысленно.
Создай 1 000 - 10 000 различных курсов по одной валюте и сравни результаты.
выигрыш в быстродействии должен быть никак не меньше 1.5 раза.
На мой вкус, "Гостинец" в первой строке выдает как раз правильный результат :
"Изменение курса" в первой строке не имеет смысла , т.к. пред.курс неизвестен.

63. vip 07.06.10 10:23 Сейчас в теме
(61) > Только "гостинец" по первой дате выдает неправильный результат в "Изменение курса".

Да наплюй ты на результат. Главное, шо 18%.
64. alexk-is 6544 07.06.10 10:27 Сейчас в теме
(63) Дошел до 4 и 5 запросов в пакете - случился взрыв мозга. Иду за кофе...
65. Ish_2 1112 07.06.10 10:40 Сейчас в теме
(64) "Взрыв мозга" , на самом деле, - это мне минус.
Нужно было оставить комментарии.
66. anig99 2852 07.06.10 12:58 Сейчас в теме
(65)(64) а комментарии - это моя статья про нарастающие итоги (: Как раз разбиение соединений сначала на более крупные периоды, а потом на более мелкие.
67. Ish_2 1112 07.06.10 13:03 Сейчас в теме
(66) Саша, ты не в теме. Совсем.
68. anig99 2852 07.06.10 14:01 Сейчас в теме
(67) думаешь, если тут коты в тапки ссут, то я не в теме? Я посмотрел гостинец из (60)... Разве там не продемонстрировано применение сложного алгоритма для оптимизации времени выполнения запроса?
70. Ish_2 1112 07.06.10 14:09 Сейчас в теме
(68) Да , это так . Этот подход применил Алексей - я лишь повторил его.
Дело совсем не в этом .
Всё крутится вокруг "фишки"( Алексей употребил это слово) в (39).
121. Ish_2 1112 08.06.10 11:10 Сейчас в теме
Давай уж добьем до конца этот вопрос.
(68) ,(107) Саша и Артур , просьба :
Пожалуйста , протестируйте и сравните на предмет быстродействия:
1. Прикрепленную обработку в (60) Гостинец.epf
2. В текущей теме в разделе "файлы" четвертый файл "пример с оптимизацией" Пример 3_2.epf.

Нужно в БП , а потом в УТ создать ежедневные разные курсы по одной валюте за 12 лет и запустить обработки 1 и 2. Сравнить время выполнения .
Не откажите хорошему человеку. Вы нас рассудите с Алексеем.

P.s. Было бы хорошо - и для файлового варианта и для клиент-серверного.
127. artbear 1563 08.06.10 12:48 Сейчас в теме
(121) Пока некогда тестировать :(
пока только иногда почитываю
123. Ish_2 1112 08.06.10 11:48 Сейчас в теме
+(68),(107) Виноват. Алексей уже успел поменять на новую версию свой "пример3_2" .
Сравнивать нужно с первоначальным примером.
Прикрепленные файлы:
Пример3_2_Первоначальный.epf
124. alexk-is 6544 08.06.10 12:23 Сейчас в теме
(123) А не проще из "Гостинец" вырезать 3 строки?
ИНДЕКСИРОВАТЬ ПО
Период1,
Период2
125. Abadonna 3968 08.06.10 12:28 Сейчас в теме
(124) А не проще прекратить быстродействиями меряться? :D
Практической пользы - практически ноль. Ну, одна за 17 секунд, другая за 15...
Ну и фигли? ;)
Нажал я кнопочку "Загрузить" и пишу этот коммент (а менеджер по асе девочку охмуряет).
Один фиг загрузит быстрее, чем вышеизложенное ;)
126. alexk-is 6544 08.06.10 12:28 Сейчас в теме
(123) :)
- У меня программа в 2 раза меньше твоей, работает в 10 раз быстрее, имеет изумительное юзабилити.
- Ну, и что? Зато моя работает правильно.


А если серьезно, то мне понравилось решение в "Гостинец", иначе не появился бы "Пример3_3".
128. Ish_2 1112 08.06.10 12:54 Сейчас в теме
(126) Черт возьми ! Возник спор - нужно установить факты.
После того как факты установлены - делиться размышлизмами и делать выводы .
129. alexk-is 6544 08.06.10 13:19 Сейчас в теме
(128) Как мне кажется, особо спорить не о чем.

В SQL версии
"Гостинец" работет немного быстрее как в вариантах с индексами, так и без индексов

В файловой версии
При использовании индексов "Гостинец" также быстрее
"Пример3_3" быстрее без индексов, но это скорее исключение - может дело в базе или в расположении звезд

Мне, например, гораздо интереснее - почему с индексами в файловой версии работает значительно медленнее чем без индексов.
130. Ish_2 1112 08.06.10 14:54 Сейчас в теме
(129) Точнее всё-таки сформулировать так :
Почему при ЯВНО заданном индексе для врем.таблице в файловой базе наблюдаются жесткие тормоза ?
И почему при НЕЯВНО заданном индексе (ведь наверняка его создал оптимизатор запроса) тормозов не наблюдается.
131. artbear 1563 08.06.10 15:11 Сейчас в теме
(130) А на скуле проверяли с индексами и без ?
132. alexk-is 6544 08.06.10 15:36 Сейчас в теме
(131) Лучшее время из 10 тестов. MS SQL 2005. УПП 1.2.

С индексами
Время выполнения Гостинец.epf - 0,484 сек
Время выполнения Пример3_2.epf - 0,469 сек

Без индексов
Время выполнения Гостинец.epf - 0,343 сек
Время выполнения Пример3_2.epf - 0,516 сек
82. alexk-is 6544 07.06.10 15:54 Сейчас в теме
(60) Загрузил курсы валют за 12 лет. Получил следующие результаты для файловой версии.

Вариант 3. Обычное соединение. Завершено за ~35,5 сек.
Вариант 3. Оптимизированное соединение. Завершено за ~12,5 сек.
Гостинец. Оптимизированное соединение. Завершено за ~12,5 сек.
Починенный Гостинец. Оптимизированное соединение. Завершено за ~12,5 сек.

Разница в производительности очень не значительная :(
101. Ish_2 1112 07.06.10 18:20 Сейчас в теме
(82) Давай подробнее.
Рассматривается файловый вариант. Исследуются две обработки
"Гостинец.epf"
и "Пример 3_2" , скачанный в текущей теме сегодня в 18-20 мск.

Количество ежедневных курсов (подряд) с 1998 года по сегодняшний день составило в тестовой базе БП 1.6 - 4400 шт.
Замер времени исполнения запроса производился средствами ТВОЕЙ обработки.
Каждая обработка запускалась 3 разF.

Время выполнения Гостинец.epf - ~ 11.7 сек
Время выполнения Пример3_2.epf - ~ 17.7 сек
Выигрыш 1.5 раза.

Кто нас рассудит ? Помогите , люди добрые !
104. alexk-is 6544 07.06.10 22:16 Сейчас в теме
(101) Так. Был немного занят - делал сыну мечи.
Итак дома загрузил курсы в БП 1.6 - 8491 запись в регистре сведений Курсы валют по EUR и USD с 01.01.1999

Время выполнения Гостинец.epf - ~ 12.3 сек
Время выполнения Пример3_2.epf - ~ 12.6 сек
Время выполнения Пример3.epf - ~ 35.5 сек

51. Ish_2 1112 04.06.10 14:54 Сейчас в теме
Так я то текст темы смотрю ! А ты в файлах .
56. alexk-is 6544 04.06.10 15:27 Сейчас в теме
(51) "Пример 3" в статью вставить не решился. Не хочу пока народ пугать. В статье пока "Пример 2".
54. Ish_2 1112 04.06.10 15:08 Сейчас в теме
Представляешь , а если бы в языке запросов для
временных таблиц был возможен UPDATE ?
Ведь тогда - все эти выкрутасы с соединениеми по неравенству были не нужны !
Одна команда UPDATE - и всё !
58. anig99 2852 04.06.10 15:44 Сейчас в теме
(54) по поводу апдейта для решения проблем с нарастающими итогами говорено давно... Иначе оптимизированный запрос с соединением по неравенству занимает много страниц... Некоторые "гуру" даже разбираться не хотят (:
На самом такими темпами нужно ждать 1с 8.5 или 9.0, где будет реализована возможность редактирвания ВРЕМЕННЫХ таблиц и что-то типа UPDATE.
(57) там можно в меньше, чем 15 строчек уложиться...вопрос только в производительности... А производительсноть повышается 3 способами:
1. Наращивание железа
2. Оптимизация рутинных операций путем переписывания на assemblere (или другом языке)
3. Написанием сложного и длинного алгоритма, возможно с применением математических моделей.
55. Ish_2 1112 04.06.10 15:10 Сейчас в теме
Кхе-кхе ... Придется смотреть попристальнее . Вот блин...
57. Ish_2 1112 04.06.10 15:36 Сейчас в теме
А ты опубликуй этот длиннющий пакет.
А ниже приведи текст кода в 15-20 строчек решающий эту же задачу , причем в любом варианте быстрее чем запрос.
И вывод : дескать решайте сами !
200. Yashazz 4791 05.06.11 12:24 Сейчас в теме
(57) Эстер тоже любит наворотить запрос, листингов на 70, а потом выясняется, что кодом оно решается в 20 строк и быстрее, и прозрачнее. На мой взгляд, запрос ради запроса это уже искусство, а не прагматика, реально же надо искать золотую середину.
201. Ish_2 1112 05.06.11 13:38 Сейчас в теме
(200) Бог с ним , с этим штампом о золотой середине. Кто её видел ?
Прагматика должна опираться на исходные положения :
1. Данные хранятся только на сервере.
2. Любое обращение к данным есть запрос.
3. Эффективнее преобразовывать данные там , где они хранятся. Без перегонки на клиента.
4. Переводя решение на SQL -запрос , мы делаем его технологичнее (отвязываемся от слабости клиента).

Эти исходные положения диктуют совершенно определенный взгляд на решение любой задачи.
Тошнота от циклов , if-ов , case-ов, рекурсий - нормальная реакция здорового мозга.
Понятно , что без кодинга совсем не обойтись. НО.
Корявая попытка написать запрос полезнее двух корректно написанных процедур.
Долой кодинг ! Даешь прозрачный запрос !
202. hogik 443 05.06.11 16:31 Сейчас в теме
(201)
"Переводя решение на SQL -запрос , мы делаем его технологичнее (отвязываемся от слабости клиента)."(с)
Отвязываясь от "слабости клиента"(с) происходит отвязывание и от мозгов клиента. Если мозгов (алгоритмических возможностей) "запросного" сервера хватает для решения поставленной задачи, то - да. А если не хватает? Упрощаем (извращаем) постановку задачи? Подстраиваем схему БД под средства (запросы) обработки данных? Громоздим "средний уровень"? И всё это ради утверждения "Любое обращение к данным есть запрос"(с). Откажитесь от использования только запросов, и получите "золотую середину"(с). Все так просто... :-)
203. Ish_2 1112 05.06.11 16:52 Сейчас в теме
(202) Всё как обычно, Владимир ?

а) Ничего не утверждаем,
б) ничего не предлагаем

Но :

в) спорим
в) сомневаемся ,
г) отрицаем ,
е) отказываемся ...

С одной стороны , имеете право . Так безопаснее , чем лезть на рожон
с утверждениями и предложениями : не "задолбят".
С другой стороны , блекло и тускло. Всё как обычно...
kulabuha; +1 Ответить
204. hogik 443 05.06.11 17:03 Сейчас в теме
(203)
Всё как обычно, Игорь ? :-)
Я утверждаю, предлагаю, делаю...
И если Ваш гонор не позволяет понять, даже, мои разработки, то пишите запросы дальше.
205. Ish_2 1112 05.06.11 17:05 Сейчас в теме
206. hogik 443 05.06.11 17:17 Сейчас в теме
(205)
Игорь.
Для разговора требуется от собеседников, чтобы они читали не только свои сообщения.
Или, читая, не заменяли все слова собеседника на слово - "восьмерка". У Вас это не получается...
Ок.(с) :-)
P.S.
Сделаю еще одну попытку достучаться: http://citforum.ru/database/articles/seltzer/
rudak_a; artbear; cool.vlad4; +3 Ответить
211. cool.vlad4 2 06.06.11 12:07 Сейчас в теме
212. Ish_2 1112 06.06.11 12:14 Сейчас в теме
(211) Спасибо за информацию.
69. Ish_2 1112 07.06.10 14:03 Сейчас в теме
А пока помечтаем и о другой необходимой возможности в языке запросов 1с :
указывать в полях выборки запрос . Разумеется , такая возможность давно реализована в диалектах SQL.
И тогда вместо соединения по неравенству можно следующее, многократно более эффективное :

Выбрать 
КВ.Период  как ТекущийПериод,
(Выбрать Первые 1 
КВвнутр.Период из РегистрСведений.КурсыВалют как КВвнутр
ГДЕ  КВвнутр.Период<КВ.Период  
Упорядочить ПО КВвнутр.Период Убыв) как ПредыдущийПериод 
ИЗ РегистрСведений.КурсыВалют как КВ
71. vip 07.06.10 14:19 Сейчас в теме
(69)
Разумеется , такая возможность давно реализована в диалектах SQL.

Разумеется.
И в 1С++ тоже.
Все чаще ловлю себя на мысли, что с 1С++ (в связке с FormEx, разумеется) не осталось ничего, о чем стоит помечтать.
Пора, наверное, на восьмерку. Освежить, так сказать, мечтательный раздел мозга.
72. пользователь 07.06.10 14:31
Сообщение было скрыто модератором.
...
73. пользователь 07.06.10 14:59
Сообщение было скрыто модератором.
...
76. пользователь 07.06.10 15:22
Сообщение было скрыто модератором.
...
Оставьте свое сообщение