На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:

  • Перед тем, как задать вопрос, желательно почитать документацию и воспользоваться поиском.
  • Когда задаёте вопрос, то обязательно указывайте платформу (7.7, 8.0, 8.1, 8.2, etc), причем желательно в заголовке. Если речь идёт о типовой конфигурации, то указывайте её название и релиз. Текущие версии можно посмотреть здесь.
  • Ещё раз напоминаем о необходимости соблюдать не только правила, но и законы. Уважайте авторские права.

Высказать своё мнение о модераторах раздела можно здесь: evGenius
  
> Оптимизация. "Хороший стиль" написания под 1С , (заголовок изменен модератором)
    У меня как всегда вопросы к народу хитрые ;) Вот хочу узнать, может кто обладает информацией по поводу того какие методы быстрее и насколько выполняются? :)
    Наподобие того как в ассемблере например команда MOV это 4 такта...
    Сообщение отредактировано: evGenius -
      Это парень не ООП, чтоб обсуждать подобные "параметры" :( , хотя есть определенные правила т.н.
      "хорошего стиля" - такая постановка вопроса более уместна, (в 1С не существует такого понятия как "рефакторинг" в прямом смысле) - поэтому чтобы писать хороший/эффективный "код" в 1С надо знать всего несколько правил:
      - особенность: если отчет (та же материальная ведомость в торговле) выполняется с условием отбора по группам товаров (особенно самого верхнего уровня), то для для каждой ниже лежащей (подчиненной) группы выполняется отдельный запрос. В итоге время построения отчета с условиями больше чем без оных!
      - Для уменьшения трафика сети и для разгруски сервера нужно использовать транзакции, в большенстве случаев очень сильно помогает, по крайней мере сеть сильно разгружается, и увеличивается общая производительность......
      - используй регистры! Пример: Если есть жесткая привязка документов оплаты и отгрузки к документу "Заявка" то проще сделать дополнительный регистр, в котором учитывать сумму заявки и суммы оплаты и отгрузки. Тогда тебе нужно будет просто получить итог данного регистра по конкретному документу на точку актуальности. Это будет быстрее. Но еще нужно будет создать примитивный документ корректировки данного регистра, поскольку если используются различные валюты оплаты то регистр может автоматически не закрываться
      - Обращаться к итогам в формах с табличной частью дольше, чем к реквизиту
      - получение остатков/оборотов по регистру на позицию проводимого документа - это существенно. И здесь, помимо _технически быстрого извлечения данных_ из таблиц, неважно в какой СУБД хранящихся, очень существенна _логическая_ организация данных. А, если я правильно понял, то разработчики БР именно этим и хлещутся - оптимизацией _хранения_ данных об остатках/оборотах.
      Т.е., я не хочу подменять 1С в умении вытаскивать данные из ею же организованных таблиц. Я хочу иметь лучщим образом организованные данные, чтобы результат получался быстрее по определению. На мой взгляд, только так и можно добиться увеличения производительности на порядки, а не в разы.
      - При выполнении запроса выполняется разделение его текста на две части: на серверную и на клиентскую. В серверную часть входят только краткие пути объявления внутренних переменных, в которых обращение идет только к полям регистров. Если в объявление переменной встречается длинный путь через точку, то он усекается до краткого, а остальная часть в дальнейшем обрабатывается на стороне клиента" И производительность запросов падает ниже, чем у штатного объекта "Запрос" в SQL версии :-)
      - используй прямые запросы (СКЛ)...
      - и последнее: На всех клиентах одна и та же ОС (один и тот же релиз), сет.катрочки одинаковые, драйвера одного релиза, плюс качественный монтаж кабеля и правильные сетевые настройки.
      Развлекайся! :)

      Добавлено в :
      Кстати для проверки всего вышесказанного и вообще на будущее рекомендую пользоваться утилиткой "замер производительности" из конфигуратора <_<
        Думаю, тут есть кое что интересное (в аттаче). Кстати, всё, что там сказано про SQL-версии, это правда.
        Да, и ежели внимательно отнестись к отборам в регистрах и БИ - тоже можно оочень всё ускорить.
        Прикреплённый файлПрикреплённый файлspeed_1C.zip (41.52 Кбайт, скачиваний: 2306)
          Тему закрепляю повыше, думаю, оно многим интересно будет.
            Совершенно не согласен с тем, что нужно использовать регистры.
            Регистры СОВСЕМ нельзя использовать (в запросах 1С я имею ввиду, не в SQL) если в запросе присутствует конструкция Регистр.ХХХ.ТекущийДокумент.УУУУ
            Встретился мне раз такой маразм. Был какой-то отчет по экспедиторам, выполнялся по ОДНОМУ около 20мин; хотел переписать под SQL, но проблема решилась на замену выборки из регистра на выборку по документам отгрузки. Стал делаться за 30сек :-)

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

            На регистре, который часто приходится рассчитывать, полезно ставить галочку быстрый отбор, отбор движений по имзмерениям и т.д. Наприме, регистры учета остатков, которые рассчитываются в момент проведения документов. Установка всех этих галочек замедляет запись в регистр, но ускоряет чтение из него. А чтение занимает 80-95% времени.

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

            бухгалтерский учет (до какого-то предела, наверное) гораздо быстрее работает на ДБФ, чем на SQL. Разница в скорости - в десятки раз. Дело в том, что объект "БухгалтерскиеИтоги" возможности SQL не использует совсем. Написание прямых запросов для SQL в этом случае затруднено, в индекс попасть очень трудно.

            Да! Об этом уже много раз сказано, но я повторюсь:
            для регистра 1С создает кластерный индекс по всем его измерениям, поэтому наивысшая скорость получается при указании в запросе значений для всех измерений (операция INDEX SEEK), приемлемая - при указании нескольких первых измерений (INDEX SCAN), а при указании не первых измерений поиск сводится к просмотру таблицы (TABLE SCAN) - то есть тормоза. Измерения в индексе расположены в том порядке, в котором они объявлены в 1С.
              Mechanic, почему то speed_1C.zip не скачивается - ошибка в архиве.
                Всё отлично скачивается :yes:
                  Плохой стиль :no: :
                  ExpandedWrap disabled
                    Для Н = 1 По Метаданные.Справочник() Цикл
                        С = СоздатьОбъект("Справочник."+Метаданные.Справочник(Н).Идентификатор);
                        С.ВыбратьЭлементы(0);
                        Пока С.ПолучитьЭлемент() = 1 Цикл
                            С.Удалить(1);
                        КонецЦикла;
                    КонецЦикла;


                  Хороший стиль :yes: :
                  ExpandedWrap disabled
                    Для Н = 1 По Метаданные.Справочник() Цикл
                        С = СоздатьОбъект("Справочник."+Метаданные.Справочник(Н).Идентификатор);
                        С.ВыбратьЭлементы(0);
                        Пока С.ПолучитьЭлемент() = 1 Цикл
                            С.Удалить(0);
                        КонецЦикла;
                    КонецЦикла;


                  П.С.:
                  На рабочей базе пробовать настоятельно не советую.
                    RusUdin, а ты в курсе, что выборка сбивается при удалении элемента?
                      Цитата evGenius @
                      RusUdin, а ты в курсе, что выборка сбивается при удалении элемента?

                      Проверял. Самое интересное, что не сбивается (релиз 25 по крайней мере).
                        Цитата RusUdin @
                        Проверял. Самое интересное, что не сбивается (релиз 25 по крайней мере).

                        А если удалять не все, а по какому-нибудь условию?
                          Цитата evGenius @
                          А если удалять не все, а по какому-нибудь условию?

                          Не могу сказать, таких задач перед собой не ставил. Но знаю, что с таблицами значений такое не проходит.
                          Сообщение отредактировано: RusUdin -
                            Цитата Allaire @
                            В итоге время построения отчета с условиями больше чем без оных!

                            Это неверно... С условиями запрос отрабатываютса на много быстрее, тем более если это запрос на ToySQL или на 1С++

                            -Added
                            Цитата , @
                            Плохой стиль :
                            Для Н = 1 По Метаданные.Справочник() Цикл
                            С = СоздатьОбъект("Справочник."+Метаданные.Справочник(Н).Идентификатор);
                            С.ВыбратьЭлементы(0);
                            Пока С.ПолучитьЭлемент() = 1 Цикл
                            С.Удалить(1);
                            КонецЦикла;
                            КонецЦикла;


                            Хороший стиль :
                            Для Н = 1 По Метаданные.Справочник() Цикл
                            С = СоздатьОбъект("Справочник."+Метаданные.Справочник(Н).Идентификатор);
                            С.ВыбратьЭлементы(0);
                            Пока С.ПолучитьЭлемент() = 1 Цикл
                            С.Удалить(0);
                            КонецЦикла;
                            КонецЦикла;


                            П.С.:
                            На рабочей базе пробовать настоятельно не советую.

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

                            Хороший Стиль:

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

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


                              Имхо тоже плохой стиль.
                              1) Использовать конструкцию Перейти нужно только в крайнем случае.
                              2) В подобных случаях необходимо использовать механизм тразакций.
                                Цитата Pavlovsky @
                                2) В подобных случаях необходимо использовать механизм тразакций.

                                Причём если справочники в базе объёмные, то транзакцию нужно делать не одну, а порциями по некоторому количеству данных. Иначе удаление будет дико тормозить и отожрёт очень много памяти.
                                    Пример "Как нельзя писать код"
                                    Система самописная, писалась местными "умельцами" с нуля и лет 7 назад, если не больше. В принципе достаточно неплохая, но местами встречаются такие косяки, что плакать хочется.

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

                                    ExpandedWrap disabled
                                      КонПериода = КонецДня(Дата(Год(НачПериода)+1, Месяц(НачПериода), День(НачПериода)));


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

                                    ExpandedWrap disabled
                                      КонПериода = КонецДня(ДобавитьМесяц(НачПериода, 12));


                                    Пока поставил себе зарубку переписать этот кусок кода и начал разбираться дальше - что же именно вызвало ошибку всего в двух документах. Посмотрев в отладчике значение НачПериода, увидел что там 29-02-2016, високосный год, Карл, а прибавив год к дате как описано выше, получаем 29 февраля 2017, а такой даты не существует. Сразу же переписал с использованием функции ДобавитьМесяц, и все заработало. Руки бы оторвал за такую работу с датой >:(

                                    Сообщения были разделены в тему "Flood"
                                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                    0 пользователей:


                                    Рейтинг@Mail.ru
                                    [ Script execution time: 0,0587 ]   [ 15 queries used ]   [ Generated: 19.03.24, 09:53 GMT ]