|
Можно ли оптимизировать данный запрос? | ☑ | ||
---|---|---|---|---|
0
SherifSP
22.04.13
✎
10:48
|
Конфа УПП, в типовом общем модуле в функции ОпределитьНаличиеДвиженийПоРегистратору(ДокументСсылка) есть запрос, который выполняется в цикле, как я помню это не оптимально, кто что думает по этому поводу?
Для Каждого Движение ИЗ МетаданнныеДокумента.Движения Цикл // в запросе получаем имена регистров, по которым есть хотя бы одно движение // например, // ВЫБРАТЬ Первые 1 «РегистрНакопления.ТоварыНаСкладах» // ИЗ РегистрНакопления.ТоварыНаСкладах // ГДЕ Регистратор = &Регистратор // имя регистра приводим к Строка(200), см. ниже ТекстЗапроса = ТекстЗапроса + " |" + ?(ТекстЗапроса = "", "", "ОБЪЕДИНИТЬ ВСЕ ") + " |ВЫБРАТЬ ПЕРВЫЕ 1 ВЫРАЗИТЬ(""" + Движение.ПолноеИмя() + """ КАК Строка(200)) КАК Имя ИЗ " + Движение.ПолноеИмя() + " ГДЕ Регистратор = &Регистратор"; // если в запрос попадает более 256 таблиц – разбиваем его на две части // (вариант документа с проведением по 512 регистрам считаем нежизненным) счетчик_таблиц = счетчик_таблиц + 1; Если счетчик_таблиц = 256 Тогда Прервать; КонецЕсли; КонецЦикла; Запрос = Новый Запрос(ТекстЗапроса); ЗАпрос.УстановитьПараметр("Регистратор", ДокументСсылка); // при выгрузке для колонки «Имя» тип устанавливается по самой длинной строке из запроса // при втором проходе по таблице новое имя может не «влезть», по этому сразу в запросе // приводится к строка(200) ТаблицаЗапроса = Запрос.Выполнить().Выгрузить(); |
|||
1
Maxus43
22.04.13
✎
10:51
|
Текст запроса собюирается в цикле, а не запрос в цикле
|
|||
2
SherifSP
22.04.13
✎
10:52
|
(1) Вижу, но все же, замер показал 2 секунды на данном запросе
|
|||
3
Classic
22.04.13
✎
10:53
|
(0)
Нормальный такой запрос. Единственный его недостаток - если идет блокировка какой-то таблицы, то фиг вычислишь, что за таблица. |
|||
4
МихаилМ
22.04.13
✎
10:53
|
ВЫБРАТЬ ПЕРВЫЕ без сортировки увольнять надо
для подобных проверок существует exist (в 1с в ) нечего отимизировать тк нет текста запроса. |
|||
5
Maxus43
22.04.13
✎
10:53
|
(2) и причем тут замер? Как ещё ты определишь по каким регистрам есть движения у документа?
|
|||
6
Maxus43
22.04.13
✎
10:53
|
(4) Вы предлагаете уволить сотрудников 1с чтоли?
|
|||
7
Галахад
гуру
22.04.13
✎
10:54
|
(2) Ну две секунды. Много, что-ли? Или эти секунды в цикле?
|
|||
8
Classic
22.04.13
✎
10:55
|
(4)
Ну напиши текст запроса с учетом экзиста. Посмотри как он будет выполняться |
|||
9
SherifSP
22.04.13
✎
10:55
|
(5) Движения, не покатит?
|
|||
10
Classic
22.04.13
✎
10:56
|
(9)
Сразу доставать в память всю таблицу? |
|||
11
SherifSP
22.04.13
✎
10:56
|
(7) Нет, но есть еще кусок, который выполняется 2 секунды, тоже типовой, это помимо мелких транзакций, думаю это не кошерно по времени
|
|||
12
H A D G E H O G s
22.04.13
✎
11:00
|
2 секунды - это огого на самом на деле.
|
|||
13
Maxus43
22.04.13
✎
11:04
|
(12) не то в консерватории что-то, у меня и тебя не 2 секунды же эта хрень
|
|||
14
ДенисЧ
22.04.13
✎
11:05
|
Натыкался я на этот запрос...
Там уже некуда, там идет clustered index seek - быстрее просто некуда... |
|||
15
Maxus43
22.04.13
✎
11:05
|
(9) дольше будет, их надо ещё Прочитать() каждый чтоб понять есть ли там что. а запрос к движениям шустрей
|
|||
16
Нуф-Нуф
22.04.13
✎
11:08
|
получить объект по ссылке. получить движения. перебрать коллекцию движений.
|
|||
17
Maxus43
22.04.13
✎
11:08
|
(16) и что?
|
|||
18
ДенисЧ
22.04.13
✎
11:09
|
(16) Свободен...
|
|||
19
ДенисЧ
22.04.13
✎
11:09
|
(16) Берём документ РСВ. Читаем его движения (а их там 4 000 000). Сколько по времени? :-)
|
|||
20
Classic
22.04.13
✎
11:10
|
(16)
Для каждого движения делать неявный запрос к базе, доставать всю таблицу движения в память, получать первую строку. Жесть |
|||
21
Нуф-Нуф
22.04.13
✎
11:11
|
(19) если у тебя есть такой документ - то сделай ради теста - СсылкаРСВ.ПолучитьОбъект().Движения
|
|||
22
ДенисЧ
22.04.13
✎
11:11
|
(21) .Прочитать - около минуты. Дальше?
|
|||
23
ДенисЧ
22.04.13
✎
11:11
|
И то, если не вылетит на аут оф мемори.
|
|||
24
Maxus43
22.04.13
✎
11:12
|
(21) движения надо Прочитать ещё
|
|||
25
Нуф-Нуф
22.04.13
✎
11:13
|
(22) причем здесь прочитать?
|
|||
26
Classic
22.04.13
✎
11:15
|
(25)
Запрос из (0) получает по каким регистрам были движения. СсылкаРСВ.ПолучитьОбъект().Движения - это список всех регистров, по которым МОГЛИ БЫТЬ движения |
|||
27
H A D G E H O G s
22.04.13
✎
11:15
|
(25) Притом.
|
|||
28
Maxus43
22.04.13
✎
11:15
|
(25) цель (0) - понять если ли движения у документа. Если док двигает РН, это не значит что там что-то записано
|
|||
29
Нуф-Нуф
22.04.13
✎
11:19
|
все. посыпал голову пеплом и ушел.
|
|||
30
Fragster
гуру
22.04.13
✎
11:22
|
этот кусок из типовой выпиливать надо нафиг
|
|||
31
Classic
22.04.13
✎
11:23
|
(30)
И что делать? Это обычно перед удалением движений выполняется |
|||
32
Fragster
гуру
22.04.13
✎
11:23
|
вообще, емнип, в данном куске была еще запись пустых наборов при обходе
|
|||
33
Fragster
гуру
22.04.13
✎
11:24
|
(31) ЕМНИП, тормозил (32). а чтобы не тормозил (0) - надо не забывать делать регламентное обслуживание базы, переиндексирование там, реструктуризацию (это если физически возможно)
|
|||
34
Classic
22.04.13
✎
11:27
|
(33)
А что план запроса по этому поводу говорит, там скан идет по всем движениям документа, или по одному движению с каждого регистра? |
|||
35
Maxus43
22.04.13
✎
11:28
|
(32) в этом куске у меня нет записи пустых, вообще он есть дальше, если движения нашлись. А как ещё ты удалишь движения не записывая пустой набор?)
|
|||
36
Fragster
гуру
22.04.13
✎
11:38
|
(34) кластеред индекс сик должен быть
(35) при перепроведении зачем удалять? надо перезаписывать просто... |
|||
37
ДенисЧ
22.04.13
✎
11:38
|
(34) см (14)...
|
|||
38
Maxus43
22.04.13
✎
11:40
|
(36) дак не выпиливать надо его тогда уж, а допиливать
|
|||
39
Maxus43
22.04.13
✎
11:41
|
(38)+ да и то не факт. Меняешь операцию например - движения по другим регистрам пойдут, в процедуры "перезаписи" старых регистров и не зайдёт. Так что как бы... пусть так лучше, меньше возможных ошибок
|
|||
40
Classic
22.04.13
✎
11:43
|
(36)
"при перепроведении зачем удалять? надо перезаписывать просто..." Тогда проведение надо делать гарантированно по всем движениям. Большая такая ловушка для невнимательных получается. |
|||
41
Fragster
гуру
22.04.13
✎
11:43
|
(39) специально флаг "записывать" сделали
|
|||
42
Maxus43
22.04.13
✎
11:44
|
(41) какой флаг? Как ты определишь ЧТО надо перезаписать? Всё?
|
|||
43
notton
22.04.13
✎
11:45
|
(0) распараллелить удаление фоновыми заданиями )
|
|||
44
Широкий
22.04.13
✎
11:45
|
(4) "ВЫБРАТЬ ПЕРВЫЕ без сортировки увольнять надо "
Поясни |
|||
45
Classic
22.04.13
✎
11:46
|
(43)
Это часть обработки проведения. Распаралелить проведение? |
|||
46
notton
22.04.13
✎
11:48
|
(45) так тоже можно )
|
|||
47
Maxus43
22.04.13
✎
11:50
|
(46) дай бог чтоб успело удалится фоновым, пока туда сам док ничо не записал :)
|
|||
48
Classic
22.04.13
✎
11:51
|
(46)
И че с транзакциями будет? |
|||
49
H A D G E H O G s
22.04.13
✎
11:52
|
(47) Я делал удаление в фоновых. Упиралось в скорость записи SQL сервера (вероятнее всего оно) и выигрыша было 0.
|
|||
50
H A D G E H O G s
22.04.13
✎
11:53
|
(44) Чтобы МихаилМ что-то пояснил из своего потока сознания? Да вы верно шутите!
|
|||
51
Maxus43
22.04.13
✎
11:53
|
(48) фоновые можно запустить в рамках одной транзакции, видел реализацию
|
|||
52
Fragster
гуру
22.04.13
✎
11:57
|
(42) запрос из (0) не должен тормозить (если база обслужена нормально). Как правило тормозит удаление наборов. Так вот, вместо удаления - у соответствующих наборов в Движениях" можно выставить флаг "записывать", тогда они при записи сами запишутся. Если они не были изменены - пустыми наборами, если были - то только 1 раз уже заполненными новыми записями.
|
|||
53
Fragster
гуру
22.04.13
✎
11:59
|
(49) а ты тест мой делал? по регистрам рост был с ростом количества потоков?
|
|||
54
Широкий
22.04.13
✎
11:59
|
(0) Я вижу в запросе только один недочет - это блокировка на чтение сразу всех таблиц вошедших в запрос.
ИМХО лучше бы крутить в цикле по одному регистру. |
|||
55
Fragster
гуру
22.04.13
✎
12:00
|
(54) там по диапазону индекса все равно блокировка
|
|||
56
Широкий
22.04.13
✎
12:01
|
+54 Мне даже кажется что дольше будет обращения к метаданным , чем регистру
"Движение.ПолноеИмя()" |
|||
57
notton
22.04.13
✎
12:02
|
(0) на пакет можно еще переделать, возможно это уменьшит блокировки
|
|||
58
Широкий
22.04.13
✎
12:02
|
(55) Но блокировка то все равно на все таблицы будет
|
|||
59
H A D G E H O G s
22.04.13
✎
12:03
|
(53) Нет, не делал. Последнее время - некогда.
|
|||
60
Maxus43
22.04.13
✎
12:03
|
(52) пробовал? этим флагом не играл..
|
|||
61
Classic
22.04.13
✎
12:04
|
(52)
А где этот флаг? (54) Не на чтение, а на запись. Почему это минус? |
|||
62
H A D G E H O G s
22.04.13
✎
12:05
|
(56) Да ладно. Эти метаданные до этого уже раз 100 запрашивались, все давно уже в кэше.
|
|||
63
Широкий
22.04.13
✎
12:10
|
А хотя наверно пофиг.. Он итоги не блокирует.
Читает только свои записи. |
|||
64
Fragster
гуру
22.04.13
✎
12:12
|
(61)
РегистрНакопленияНаборЗаписей.<Имя регистра накопления>.Записывать (AccumulationRegisterRecordSet.<Имя регистра накопления>.Write) РегистрНакопленияНаборЗаписей.<Имя регистра накопления> (AccumulationRegisterRecordSet.<Имя регистра накопления>) Записывать (Write) Использование: Чтение и запись. Описание: Тип: Булево. Ложь - не происходит записи набора в информационную базу при вызове Записать коллекции движений документа, которой принадлежит набор, а также при стандартной обработке проведения документа, если значение свойства метаданного документа "Запись движений при проведении" в Конфигураторе выставлено в "Записывать выбранные". Доступность: Сервер, толстый клиент, внешнее соединение. |
|||
65
Широкий
22.04.13
✎
12:12
|
Вот это не понятно
Если счетчик_таблиц = 256 Тогда Прервать; КонецЕсли; 1. Ограничение вроде как убрали 2. Что за дикий документ по 256 регистрам проходит. 3. Как посчитана РЛС |
|||
66
hhhh
22.04.13
✎
12:12
|
(0) это древний кусок дерьма. Он был в БП 1.6 и соответственно в УПП. В БП 2.0 и в 3.0 естественно всё оптимизировали. Проверяют только те регистры, которые надо проверять.
Если ВыборочноОчищатьРегистры Тогда СписокРегистровДляОчисткиДвижений = Новый Массив; СписокРегистровДляОчисткиДвижений.Добавить(Тип("РегистрНакопленияНаборЗаписей.РасходыПриУСН")); КонецЕсли; //Очистка движений документа Для Каждого Движение ИЗ ДокументОбъект.Движения Цикл Если ВыборочноОчищатьРегистры И (СписокРегистровДляОчисткиДвижений.Найти(ТипЗнч(Движение))<>неопределено) Тогда Продолжить; КонецЕсли; Движение.Очистить(); КонецЦикла; //Запись пустых наборов движений в ИБ(очистка старых движений) Для Каждого Движение ИЗ ДокументОбъект.Движения Цикл Если (ВыборочноОчищатьРегистры И (СписокРегистровДляОчисткиДвижений.Найти(ТипЗнч(Движение))<>неопределено)) ИЛИ НЕ ВыборочноОчищатьРегистры Тогда Если Движение.Количество() > 0 Тогда ПозицияТочки = Найти(Строка(Движение), "."); ТипРегистра = Лев(Строка(Движение), ПозицияТочки - 13); ИмяРегистра = СокрП(Сред(Строка(Движение), ПозицияТочки + 1)); ЕСли ТипРегистра = "РегистрНакопления" Тогда МетаданныеНабора = Метаданные.РегистрыНакопления[ИмяРегистра]; Набор = РегистрыНакопления[ИмяРегистра].СоздатьНаборЗаписей(); ИначеЕсли ТипРегистра = "РегистрБухгалтерии" Тогда МетаданныеНабора = Метаданные.РегистрыБухгалтерии[ИмяРегистра]; Набор = РегистрыБухгалтерии[ИмяРегистра].СоздатьНаборЗаписей(); ИначеЕсли ТипРегистра = "РегистрСведений" Тогда МетаданныеНабора = Метаданные.РегистрыСведений[ИмяРегистра]; Набор = РегистрыСведений[ИмяРегистра].СоздатьНаборЗаписей(); ИначеЕсли ТипРегистра = "РегистрРасчета" Тогда МетаданныеНабора = Метаданные.РегистрыРасчета[ИмяРегистра]; Набор = РегистрыРасчета[ИмяРегистра].СоздатьНаборЗаписей(); КонецЕсли; Если НЕ ПравоДоступа("Изменение", МетаданныеНабора) Тогда // отсутствуют права на всю таблицу регистра СообщитьОбОшибке("Нарушение прав доступа", Отказ, Строка(Движение)); Возврат; КонецЕсли; Набор.Отбор.Регистратор.Установить(ДокументОбъект.Ссылка); Иначе Набор = Движение; КонецЕсли; Попытка Набор.Записать(); Исключение // возможно «сработал» RLS или механизм даты запрета изменения СообщитьОбОшибке(ОписаниеОшибки(), Отказ, Набор); ВызватьИсключение "Операция не выполнена"; КонецПопытки; КонецЕсли; КонецЦикла; |
|||
67
Fragster
гуру
22.04.13
✎
12:13
|
(66) все равно нафиг
|
|||
68
Fragster
гуру
22.04.13
✎
12:14
|
единственный плюс - в режиме полных прав запись идет
|
|||
69
Fragster
гуру
22.04.13
✎
12:14
|
но при перепроведении - запись идет два раза
|
|||
70
Fragster
гуру
22.04.13
✎
12:15
|
с соответствующим пересчетом итогов
|
|||
71
Широкий
22.04.13
✎
12:15
|
(69) Штатно она и так два раза идет
|
|||
72
Maxus43
22.04.13
✎
12:15
|
(66) а как это вот формирутеся?
Если ВыборочноОчищатьРегистры Тогда СписокРегистровДляОчисткиДвижений = Новый Массив; СписокРегистровДляОчисткиДвижений.Добавить(Тип("РегистрНакопленияНаборЗаписей.РасходыПриУСН")); КонецЕсли; жёско прописано в каждом документе? |
|||
73
Fragster
гуру
22.04.13
✎
12:16
|
(71) я и говорю - надо выпиливать
|
|||
74
Maxus43
22.04.13
✎
12:21
|
(73) слишком много переделывать, чтоб заюзать Записывать.
Переделывать везде причем. 1с не пойдёт на это, вставит (66) в УПП 2.0 скорей всего, иль чо там щас, в тестовой? |
|||
75
Fragster
гуру
22.04.13
✎
12:21
|
(74) так ведь все равно копро и двойная запись. а перепиливать можно частично - начиная по самым проблемным местам...
|
|||
76
Maxus43
22.04.13
✎
12:24
|
(75) как изменили в УПП 2.0 ознакомительной - так и будет, возможно посчитали (и не без оснований), что в данном случае выхлопа будет слишком мало, исходя из объёма работ. хз
|
|||
77
notton
22.04.13
✎
12:25
|
(74) уп 2.0
)) // Функция формирует массив имен регистров, по которым документ имеет движения. // Вызывается при подготовке записей к регистрации движений. // Функция ПолучитьМассивИспользуемыхРегистров(Регистратор, Движения, МассивИсключаемыхРегистров = Неопределено) Экспорт Запрос = Новый Запрос; Запрос.УстановитьПараметр("Регистратор", Регистратор); Результат = Новый Массив; МаксимумТаблицВЗапросе = 256; СчетчикТаблиц = 0; СчетчикДвижений = 0; ВсегоДвижений = Движения.Количество(); ТекстЗапроса = ""; Для Каждого Движение Из Движения Цикл СчетчикДвижений = СчетчикДвижений + 1; ПропуститьРегистр = МассивИсключаемыхРегистров <> Неопределено И МассивИсключаемыхРегистров.Найти(Движение.Имя) <> Неопределено; Если Не ПропуститьРегистр Тогда Если СчетчикТаблиц > 0 Тогда ТекстЗапроса = ТекстЗапроса + " |ОБЪЕДИНИТЬ ВСЕ |"; КонецЕсли; СчетчикТаблиц = СчетчикТаблиц + 1; ТекстЗапроса = ТекстЗапроса + " |ВЫБРАТЬ ПЕРВЫЕ 1 |""" + Движение.Имя + """ КАК ИмяРегистра | |ИЗ " + Движение.ПолноеИмя() + " | |ГДЕ Регистратор = &Регистратор |"; КонецЕсли; Если СчетчикТаблиц = МаксимумТаблицВЗапросе Или СчетчикДвижений = ВсегоДвижений Тогда Запрос.Текст = ТекстЗапроса; ТекстЗапроса = ""; СчетчикТаблиц = 0; Если Результат.Количество() = 0 Тогда Результат = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("ИмяРегистра"); Иначе Выборка = Запрос.Выполнить().Выбрать(); Пока Выборка.Следующий() Цикл Результат.Добавить(Выборка.ИмяРегистра); КонецЦикла; КонецЕсли; КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции |
|||
78
Лефмихалыч
22.04.13
✎
12:27
|
Может попробовать использовать соединение вместо объединения?
ВЫБРАТЬ КОЛИЧЕСТВО(рег1.Регистратор) как Рег1, КОЛИЧЕСТВО(Рег2.Регистратор) КАК Рег 2 ИЗ РегистрНакопления.Рег1, РегистрНакопления.Рег2 ГДЕ Рег1.Регистратор = &Регистратор И Рег2.Регистратор = &Регистратор ?.. Ну и там поиграться с разными агрегатными функциями. Как минимум тут не будет уходить время на преобразования строк к строкам |
|||
79
Лефмихалыч
22.04.13
✎
12:28
|
+(78) хотя надо еще понять, что сервер 1С с этим запросом сделает, но субъективно это должно быть легче, чем "ПЕРВЫЕ 1" и "объединить ВСЕ"
|
|||
80
notton
22.04.13
✎
12:29
|
(79) или пакет запросов? (57)
|
|||
81
Лефмихалыч
22.04.13
✎
12:31
|
(80) скорее "И", а не "ИЛИ"
|
|||
82
Maxus43
22.04.13
✎
12:34
|
(77) ну значит ничо не изменилось)
|
|||
83
Fragster
гуру
22.04.13
✎
12:35
|
(82) ну почему же... записи наборов нету, возврат имен регистров...
|
|||
84
Fragster
гуру
22.04.13
✎
12:35
|
(83)+ надо смотреть дальше
|
|||
85
Maxus43
22.04.13
✎
12:36
|
(83) у меня и щас так, у тебя неправильная УПП, я ж писал что запись не тут
|
|||
86
Maxus43
22.04.13
✎
12:37
|
у меня 1.2.27 древняя
|
|||
87
Fragster
гуру
22.04.13
✎
12:38
|
(85) у меня не УПП, код тот же, только запись в той же функции (ну и название немного другое).
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |