НайденныйЭлемент Справочники.СправочникЭскалация.НайтиПоКоду(Строка(Формат(Выборка.Колонка1,ЧЦ9 ЧВН ЧГ)))


Задание 1.
Режим совместимости был убран из-за того, что возникала эскалация на таблицу РегистрНакопления3 при проведении Документа7. Т.к. в документе большое количество строк в ТЧ.
Отключено автоматическое перемещение границы последовательности.
В обработке проведения док-та ПоступленияТоваров была закомментированы строки:
Движения.ТоварныеЗапасы.БлокироватьДляИзменения = Истина;
Движения.Взаиморасчеты.БлокироватьДляИзменения = Истина;
Т.к. они препятствуют одновременному проведения Поступлений. И не требуются исходя из логики приложения.
4. В документе РасходТовара, в обработке проведения была добавлена строчка Движения.ТоварныеЗапасы.БлокироватьДляИзменения = Истина;
Т.к. происходила взаимоблокировка из-за запроса контроля остатков.
В документе8, изменен тест запроса на использование Временных таблиц, т.к. возникало сканирование таблицы индекса. Новый тест:
«ВЫБРАТЬ
Документ8Товары.Товар
ПОМЕСТИТЬ ТабИЗ
Документ.Документ8.Товары КАК Документ8Товары
ГДЕ
Документ8Товары.Ссылка = &Ссылка
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
Таб.ТоварИЗ
Таб КАК Таб»
В обработке ВыгрузкаДокументовСОбоснованиемОтгрузки изменен тест запроса, т.к. необходимо чтобы запрос выбирал только нужный тип документов.
"ВЫБРАТЬ
|ТоварныеЗапасы.Регистратор.Номер КАК Номер,
|ТоварныеЗапасы.Регистратор.Дата КАК Дата,
|ВЫРАЗИТЬ(ТоварныеЗапасы.Регистратор.ОбоснованиеОтгрузки КАК СТРОКА(100)) КАК ОбоснованиеОтгрузки|ИЗ
|РегистрНакопления.ТоварныеЗапасы КАК ТоварныеЗапасы|ГДЕ
|ТоварныеЗапасы.Период МЕЖДУ ДАТАВРЕМЯ(2007, 1, 1) И ДАТАВРЕМЯ(2014, 12, 31, 23, 59, 59)
|И (ВЫРАЗИТЬ(ТоварныеЗапасы.Регистратор.ОбоснованиеОтгрузки КАК СТРОКА(100))) <> """"
|И ТоварныеЗапасы.Регистратор ССЫЛКА Документ.ОперацияПоУчетуТоваров|
|СГРУППИРОВАТЬ ПО
|ТоварныеЗапасы.Регистратор.Номер,
|ТоварныеЗапасы.Регистратор.Дата,
|ВЫРАЗИТЬ(ТоварныеЗапасы.Регистратор.ОбоснованиеОтгрузки КАК СТРОКА(100))"
В обработке ВыгрузкаРасходовСДвижениями изменен тест запроса, т.к. необходимо чтобы запрос выбирал только нужный тип документов.
"ВЫБРАТЬ
|РасходТовараТовары.Ссылка.Дата,
|РасходТовараТовары.Ссылка.Номер,
|РасходТовараТовары.Ссылка.Покупатель,
|ТоварныеЗапасы.Товар,
|РасходТовараТовары.Количество КАК КоличествоВДокументе,
|ТоварныеЗапасы.Количество КАК КоличествоВРегистре|ИЗ
|РегистрНакопления.ТоварныеЗапасы КАК ТоварныеЗапасы|ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РасходТовара.Товары КАК РасходТовараТовары|ПО ТоварныеЗапасы.Регистратор.Ссылка = РасходТовараТовары.Ссылка|ГДЕ
|ГОД(РасходТовараТовары.Ссылка.Дата) = 2015
|И ТоварныеЗапасы.Регистратор ССЫЛКА Документ.РасходТовара";
В обработке ПроведениеДокументовВТранзакции, в процедуре ПерепровестиДокументы была отключена транзакция. Хоть единая транзакция и ускоряет запись, но т.к. строк в ТЧ документов очень много, прироста скорости это не дает, а ведет к эскалации блокировок на сервере 1С предприятия.
Был проведен эксперимент, с отключением эскалации блокировок на таблицу, на SQL сервере (описание на сайте gilev.ru). Т.к. система работала стабильно, так и оставил.
В результате получился такой график в ЦУП:

Задание 2.
На моем компьютере максимальную скорость удалось получить, если использовать вместо основной таблицы, таблицу оборотов РН и выполнять запрос и запись в файлы в фоновых заданиях.
Скорость увеличилась с 57 до 20 сек.
Дальнейшие манипуляции приводили только к замедлению выгрузки. Если на сервере достаточно много оперативной памяти, можно попробовать сделать один запрос к регистру, выбрав в нем обороты по всем складам и поместив результат в таблицу. Дальнейшие запросы проводить уже к ней.
Измененный тест в обработке:
&НаСервереПроцедура ВыполнитьНаСервере()

ВремяНачала = ТекущаяДата();

ТекстЗапросаСклады =
"ВЫБРАТЬ
|Склады.Ссылка КАК Склад
|ИЗ
|Справочник.Склады КАК Склады";
Запрос = Новый Запрос(ТекстЗапросаСклады);
ТЗСклады = Запрос.Выполнить().Выгрузить();

МассивЗаданий = Новый Массив;
СтруктураРезультатов = Новый Структура;

Для Каждого ТекСтрока ИЗ ТЗСклады Цикл
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(ТекСтрока.Склад);
Задание = ФоновыеЗадания.Выполнить("ФинальноеЗадание_ФоновыеЗадания.ВыполнитьЗапрос",МассивПараметров);
МассивЗаданий.Добавить(Задание);
КонецЦикла;

ФоновыеЗадания.ОжидатьЗавершения(МассивЗаданий);
ВремяОкончания = ТекущаяДата() - ВремяНачала;
Сообщить("Длительность: " + Строка(Окр(ВремяОкончания / 60, 2)) + " мин. (" + ВремяОкончания + " сек.)");

КонецПроцедурыПроцедура ВыполнитьЗапрос(МассивПараметров) Экспорт

Запрос = новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
|ТоварныеЗапасыОбороты.Товар.Наименование,
|ТоварныеЗапасыОбороты.Склад.Наименование,
|СУММА(ТоварныеЗапасыОбороты.КоличествоОборот) КАК Количество,
|ТоварныеЗапасыОбороты.Период КАК День
|ИЗ
|РегистрНакопления.ТоварныеЗапасы.Обороты(ДАТАВРЕМЯ(2010, 1, 1), ДАТАВРЕМЯ(2016, 12, 31, 23, 59, 59), День, Склад = &Склад) КАК ТоварныеЗапасыОбороты |
|СГРУППИРОВАТЬ ПО
|ТоварныеЗапасыОбороты.Товар.Наименование,
|ТоварныеЗапасыОбороты.Склад.Наименование,
|ТоварныеЗапасыОбороты.Период ";
Запрос.УстановитьПараметр("Склад",МассивПараметров);
ТЗДвижения = Запрос.Выполнить().Выгрузить();
ИмяФайла = КаталогВременныхФайлов() + "ДвиженияПоСкладу_" + СокрЛП(МассивПараметров.Наименование) + ".txt";
ЗначениеВФайл(ИмяФайла, ТЗДвижения);

КонецПроцедурыЗадание 3.
Взаимоблокировка возникает из-за разного порядка захвата ресурсов. Документ 1 и Документ 2 пытаются захватить ресурсы, которые уже захвачены. Способ решения – запись ресурсов в одинаковом порядке.
Задание 4
Основная причина – последовательный перебор всех элементов из файла. Один из вариантов решения - выполнять операции параллельно для различных блоков данных. Например, в 10 потоков.
Код в обработке:
Функция ЗагрузитьНаСервере()

ЧислоПотоков = 10;
ИмяФайлаНаСервере1С = "F:\1C\Курсы\!Оптимизация 2016\Финал\Элементы.xlsx";
ТаблицаЗначенийИзExcel = ПрочитатьЛистExcel(ИмяФайлаНаСервере1С);
СправочникЭскалация = Справочники.СправочникЭскалация;
ЧислоСтрокВТаблице = ТаблицаЗначенийИзExcel.Количество();
ТаблицаЗначенийИзExcel.Сортировать("Колонка1");
ЧислоДобавленныхЭлементов = 0;
ЧислоОбновленныхЭлементов = 0;
РазмерПорции = Цел(ЧислоСтрокВТаблице/ЧислоПотоков);

МассивЗаданий = Новый Массив;
МассивУИД = Новый Массив;
КодГраницаПредыдущегоПотока = "0";
ЭтоПоследнийПоток = Ложь;
Для НомерПотока = 1 По ЧислоПотоков Цикл
УИД = Новый УникальныйИдентификатор;
АдресХранилища = ПоместитьВоВременноеХранилище(Неопределено,УИД);
МассивУИД.Добавить(АдресХранилища);
КодГраницаТекущегоПотока = Формат(НомерПотока*РазмерПорции, "ЧЦ=9; ЧГ=");
Если (НомерПотока = ЧислоПотоков) Тогда
РазмерПорции = ЧислоСтрокВТаблице-(ЧислоПотоков*РазмерПорции)+РазмерПорции;
ЭтоПоследнийПоток = Истина;
КонецЕсли;
РазмерПорцииБезПробела = Формат(РазмерПорции, "ЧГ=");
НаборПараметров = Новый Массив;
НаборПараметров.Добавить(РазмерПорцииБезПробела);
НаборПараметров.Добавить(КодГраницаТекущегоПотока);
НаборПараметров.Добавить(КодГраницаПредыдущегоПотока);
НаборПараметров.Добавить(ЭтоПоследнийПоток);
НаборПараметров.Добавить(ТаблицаЗначенийИзExcel);
НаборПараметров.Добавить(АдресХранилища);
Задание = ФоновыеЗадания.Выполнить("ОбщийМодульКлиентСервер.ОбработатьЭлементы", НаборПараметров);
МассивЗаданий.Добавить(Задание);
КодГраницаПредыдущегоПотока = КодГраницаТекущегоПотока;
КонецЦикла;


Если МассивЗаданий.Количество() > 0 Тогда
Попытка
ФоновыеЗадания.ОжидатьЗавершения(МассивЗаданий);
Исключение
// действия в случае ошибки
КонецПопытки;
КонецЕсли;
Для каждого ТекСтрока из МассивУИД Цикл
Результат = ПолучитьИзВременногоХранилища(ТекСтрока);
ЧислоДобавленныхЭлементов = ЧислоДобавленныхЭлементов + Результат.ЧислоДобавленныхЭлементов;
ЧислоОбновленныхЭлементов = ЧислоОбновленныхЭлементов + Результат.ЧислоОбновленныхЭлементов;
КонецЦикла;

РезультатыЗагрузки = Новый Соответствие;
РезультатыЗагрузки.Вставить("ЧислоДобавленныхЭлементов", ЧислоДобавленныхЭлементов);
РезультатыЗагрузки.Вставить("ЧислоОбновленныхЭлементов", ЧислоОбновленныхЭлементов);

Возврат РезультатыЗагрузки;
КонецФункцииПроцедура на сервере в общем модуле
Процедура ОбработатьЭлементы(РазмерПорции, КодГраница, КодГраницаПредыдущегоПотока, ЭтоПоследнийПоток, ТаблицаЗначенийИзExcel,Адрес) Экспорт


ЧислоДобавленныхЭлементов = 0;
ЧислоОбновленныхЭлементов = 0;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ " + РазмерПорции + "
|Таб.Колонка1,
|Таб.Колонка2,
|Таб.Колонка3
|ПОМЕСТИТЬ ТЗ
|ИЗ
|&Таб КАК Таб |ГДЕ
|Таб.Колонка1 "+
?(ЭтоПоследнийПоток, " > " + КодГраницаПредыдущегоПотока +" ", " > " + КодГраницаПредыдущегоПотока + " И Таб.Колонка1 <= " + КодГраница + "")+"
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|ТЗ.Колонка1,
|ТЗ.Колонка2,
|ТЗ.Колонка3
|ИЗ
|ТЗ КАК ТЗ";
Запрос.УстановитьПараметр("Таб",ТаблицаЗначенийИзExcel);
Выборка = Запрос.Выполнить().Выбрать();
Счетчик = 0;
ЧислоЭлементовВТранзакции = 1000;
Пока (Выборка.Следующий()) Цикл
Если (Счетчик = 0) Тогда
НачатьТранзакцию();
КонецЕсли;
Счетчик = Счетчик + 1;
НайденныйЭлемент = Справочники.СправочникЭскалация.НайтиПоКоду(Строка(Формат(Выборка.Колонка1,"ЧЦ=9; ЧВН=; ЧГ=")));
Если НЕ(ЗначениеЗаполнено(НайденныйЭлемент)) Тогда
СоздатьЭлементСправочника(Выборка);
ЧислоДобавленныхЭлементов = ЧислоДобавленныхЭлементов + 1;
ИначеЕсли (НайденныйЭлемент.Реквизит1 <> Число(Выборка.Колонка3)) Тогда
ОбновитьЭлементСправочника(НайденныйЭлемент, Выборка);
ЧислоОбновленныхЭлементов = ЧислоОбновленныхЭлементов + 1;
КонецЕсли;
Если (Счетчик = ЧислоЭлементовВТранзакции) Тогда
ЗафиксироватьТранзакцию();
Счетчик = 0;
КонецЕсли;
КонецЦикла;

Если (ТранзакцияАктивна()) Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;

Структура = Новый Структура;
Структура.Вставить("ЧислоОбновленныхЭлементов",ЧислоОбновленныхЭлементов);
Структура.Вставить("ЧислоДобавленныхЭлементов",ЧислоДобавленныхЭлементов);
ПоместитьВоВременноеХранилище(Структура,Адрес);


КонецпроцедурыЗадание 5
Думаю, что необходимо выполнить следующие действия для решения проблемы:
Снять у конфигурации режим совместимости с 8.2. Тем самым, конфигурация начнет работать в режиме уровня изоляции транзакций READ COMMITED SNAPSHOT. В этом случае, при выполнении запроса «жертвы», прочитается версия данных, которая была в базе, до начала выполнения транзакции «виновника».
Если п.1 по каким-то причинам не будет работать либо снять режим совместимости нельзя, можно попробовать создать такой индекс для таблицы, который не будет вызывать полное сканирование, а позволит выполнить поиск по нему, что так же не должно вызывать проблем при выполнении запросов по непересекающимся измерениям.
Задание 6

Задание 7
ВЫБРАТЬ
ПриходТовара.Номер,
ПриходТовара.ДатаИЗ
Документ.ПриходТовара КАК ПриходТовараЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварныеЗапасы КАК ТоварныеЗапасыПО (ТоварныеЗапасы.Регистратор = ПриходТовара.Ссылка)
ГДЕ
ТоварныеЗапасы.Регистратор ЕСТЬ NULL
Задание 8
Для решения проблемы можно использовать метод записи нескольких элементов в одной транзакции. В приведенном коде записываются блоки по 1000 элементов. Кроме того, для поля ДатаОбновления, справочника «СправочникЭскалация» можно установить признак «Индексировать».
Процедура ОбновитьЗначениеРеквизита(ТаблицаЭлементов, ИндексНачала, РазмерПроции, ДатаОбновления) Экспорт

СчТр=0;
ЧислоЭлементовВТранзакции = 1000;
// обновляем реквизит только для определенной части таблицы
Для Сч = 1 По РазмерПроции Цикл
Индекс = ?(Сч=1, ИндексНачала, Индекс+1);
Если СчТр = 0 Тогда
НачатьТранзакцию();
КонецЕсли;
СчТр = СчТр+1;

ЭлементОбъект = ТаблицаЭлементов[Индекс].Ссылка.ПолучитьОбъект();
ЭлементОбъект.Реквизит1 = ЭлементОбъект.Реквизит1 + 1;
ЭлементОбъект.ДатаОбновления = ДатаОбновления;
ЭлементОбъект.Записать();

Если СчТр = ЧислоЭлементовВТранзакции Тогда
ЗафиксироватьТранзакцию();
СчТр = 0;
КонецЕсли;

КонецЦикла;

Если ТранзакцияАктивна() Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;

КонецПроцедурыЗадание 9
Т.к. с регистрами расчета большого опыта не имею, пришлось разбираться. После анализа ожидания, посредством ЦУП, техн. журнала, и SQL Management studio удалось выяснить следующее: Ожидание возникает как по причине частичного сканирования таблицы (rid lookup), так и по причине того, что в регистре некоторые поля не проиндексированы. Средствами платформы создать необходимые индексы не получилось. Отсюда могу сделать следующие выводы: избежать подобной проблемы возможно либо организацией рабочего процесса, который не допускает одновременное проведение документов, либо проведение документов дольше чем ожидание на блокировке (20 сек). Или переходом на платформу 8.3, с отключенным режимом совместимости с 8.2.
Задание 10
Согласно описанию на сайте Майрософт, оператор RID Lookup осуществляет поиск закладки в куче при помощи заданного идентификатора строки. Причина– отсутствие необходимых полей в составе индекса.
Без вмешательство в структуру индексов, т.е. только средствами 1С избавиться от него не получилось. А средствами SQL-сервера, можно избавиться путем необходмых полей в индекс, на закладке «Включенные столбцы».
Если все необходимые поля будут в индексе, то Nested Loops не будет. Nested loops оправдан в том случае, когда ему на вход подается небольшое количество данных, как в данном случае.

Приложенные файлы

  • docx 44500545
    Размер файла: 60 kB Загрузок: 0

Добавить комментарий