Имя: Пароль:
1C
 
Оптимизация быстродействия запроса
0 bluekrab
 
22.10.15
12:41
Добрый день. Помогите оптимизировать запрос. Не могу понять, что влияет на его быстродействие.

ВЫБРАТЬ
    РеализацияТоваровУслугТовары.Номенклатура КАК Товар,
    РеализацияТоваровУслугТовары.Цена КАК Цена,
    РеализацияТоваровУслугТовары.Количество,
    РеализацияТоваровУслугТовары.ЕдиницаИзмерения КАК ЕдиницаХранения,
    РеализацияТоваровУслугТовары.Сумма,
    РеализацияТоваровУслугТовары.Ссылка.Ссылка,
    РеализацияТоваровУслугТовары.СуммаНДС,
    РеализацияТоваровУслугТовары.СтавкаНДС.Ссылка
ПОМЕСТИТЬ ВР
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
ГДЕ
    РеализацияТоваровУслугТовары.Ссылка.Ссылка В(&Регистратор)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВР.Товар,
    ВР.Количество КАК Количество,
    ВР.ЕдиницаХранения,
    ВЫРАЗИТЬ(ХозрасчетныйДвиженияССубконто.Сумма / ХозрасчетныйДвиженияССубконто.КоличествоКт КАК ЧИСЛО(10, 2)) КАК ЦенаЗакупки,
    ХозрасчетныйДвиженияССубконто.Сумма КАК СуммаЗакупки,
    ВР.Сумма КАК Сумма,
    ВР.СуммаНДС,
    ВР.Цена КАК Цена
ИЗ
    ВР КАК ВР
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(, , Счет = &Счёт, , ) КАК ХозрасчетныйДвиженияССубконто
        ПО (ХозрасчетныйДвиженияССубконто.СубконтоКт1 = ВР.Товар)
            И (ХозрасчетныйДвиженияССубконто.Регистратор = ВР.Ссылка)
1 sash-ml
 
22.10.15
12:46
ДвиженияССубконто(, , Счет = &Счёт и сюда условие на регистратор не?, , )
2 H A D G E H O G s
 
22.10.15
12:47
РеализацияТоваровУслугТовары.Ссылка.Ссылка В(&Регистратор)

на

РеализацияТоваровУслугТовары.Ссылка В(&Регистратор)
3 Рэйв
 
22.10.15
12:49
(0)Проиндексируй ВТ по Товар и Ссылка
4 asady
 
22.10.15
12:50
(0) ограничь снизу и сверху период
у тебя же тупой скан по всей таблице движений с субконто
5 mistеr
 
22.10.15
12:51
(3) ВТ вообще лишняя.
6 GANR
 
22.10.15
12:53
(0) .Ссылка.Ссылка - сразу в глаза бросилось, это точно не окажет положительного влияния на быстродействие
7 asady
 
22.10.15
12:55
8 GANR
 
22.10.15
12:55
+(6) а нельзя ли ДвиженияССубконто на ОборотыДтКт заменить?
9 User_Agronom
 
22.10.15
12:55
(1) (5) Да.
10 GANR
 
22.10.15
12:56
Ооооой... Да тут еще перед соединением с регистром последний надо по регистратору отфильтровать
11 GANR
 
22.10.15
12:57
(1) - точно (5) - не факт
12 GANR
 
22.10.15
12:58
(3) если записей в таблице менее 20 - индекс только навредит
13 GANR
 
22.10.15
13:00
и еще: Вы уверены, что в табличной части не будет дублей?
14 GANR
 
22.10.15
13:02
(0) >Не могу понять, что влияет на его быстродействие.
Да? А я не могу понять, почему этот запрос должен работать быстро.
15 ViSo76
 
22.10.15
13:11
Вместо:

ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(, , Счет = &Счёт, , ) КАК ХозрасчетныйДвиженияССубконто

Поставь:

ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(, , Регистратор В ( &Регистратор ) И Счет = &Счёт, , ) КАК ХозрасчетныйДвиженияССубконто
16 ViSo76
 
22.10.15
13:35
(6) Да там тупо будет соединение левое. Если головной таблицей станет РеализацияТоваровУслуг то провала производительности не будет, хотя я предпочитаю писать без точек всегда. Использую точку если без неё много городить придётся и точно знаю что на быстродействие эта точка не скажется.
(3) Индексация вообще никак не спасёт
(5) В данном случае ВТ лишняя на 100%. Увлечение без повода ВТ перегружает временную базу данных что сказывается на общей производительности.
17 GANR
 
22.10.15
13:39
(16) >В данном случае ВТ лишняя на 100%.
А уверены, что в выборе НЕ нужны позиции, по которым нет проводок?
18 GANR
 
22.10.15
13:39
+(17) ^в выборе
в выборКе
19 ViSo76
 
22.10.15
13:48
(17) А тебя что кто-то заставляет присоединять к проводкам документ? В место той же ВТ можно сделать выборку в документе и присоединить ЛЕВЫМ соединением проводки
20 GANR
 
22.10.15
14:13
(19) Это верно, но вот если в табличной части может быть 2 строки с одним товаром (нет технического ограничения на дубли), то ее надо сворачивать, а это лучше сделать в рамках временной таблицы. Я хочу сказать, что запрос не только медленный, но и с точки зрения правильности возвращаемых данных заведомо неверный.
21 ViSo76
 
22.10.15
14:30
(20) Тебе религия запрещает свернуть и потом присоединить движения без временной таблицы?
22 Лефмихалыч
 
22.10.15
14:33
Условия на виды субконто надо наложить еще (первый параметр)
23 GANR
 
22.10.15
14:50
(21) Не религия - оптимизатор MS SQL, который может решить, что рациональней выполнять запрос в цикле.
24 GANR
 
22.10.15
14:52
+(23) такое бывает при использовании вложенных запросов
25 ViSo76
 
22.10.15
14:55
(23) У тебя "вложенный" будет головой таблицей по этому не понимаю о каких циклах ты вещаешь
26 GANR
 
22.10.15
15:00
(25) А просто возьми и попробуй посоединять большие таблицы с вложенными запросами разными способами - лично я убедился, что это ужасно влияет на быстродействие и уже не раз переделывал такие "разработки". 1С в своих стандартах не рекомендует соединения с вложенными запросами. Свертку с их помощью - ради Бога, но соединять - никогда.
27 ViSo76
 
22.10.15
15:05
(26) В данном случае НЕТ соединений с вложенным. В начале отбирается вложенный и потом соединяется с виртуальной с нормальным отбором ( не со всеми движениями начиная от рождения Иисуса ). Зачем набрасывать на вентилятор того чего НЕТ в данном запросе?
28 GANR
 
22.10.15
15:11
(27) > НЕТ соединений с вложенным
Это заблуждение - если мы используем вложенный запрос, то оптимизатор может как угодно построить план запроса.
29 bluekrab
 
22.10.15
15:11
(15) Спасибо большое. Ваш совет помог
30 GANR
 
22.10.15
15:12
Это только визуально нам кажется, что сначала всё отберется из ВЗ
31 ViSo76
 
22.10.15
15:16
(30) Понятно что в начале будет отборы, а в конце самом левое соединение. Ты же не думаешь что виртуальная таблица уже готовая? По этому всё что ты набрасывал ранее это просто дуть на воду. Поверь в данном случае вода холодная. Какие ты ещё там циклы увидел...
32 ViSo76
 
22.10.15
15:17
(29) Тема фотографии не раскрыта
33 MadJhey
 
22.10.15
15:22
(27) любая виртуальная таблица - это вложенный запрос в SQL
34 ViSo76
 
22.10.15
15:26
(33) Опиши что будет делать MS SQL пошагово для данного запроса.

PS: Я тоже знаю КАРАТЕ, ДЗЮДО и много ещё страшных слов.
35 GANR
 
22.10.15
15:30
(34) Оптимизатор может для одного и того же запроса несколько различных планов выполнения построить на свое усмотрение. А если временную таблицу задействовать - вот тут можно четко знать что произойдет.
36 ViSo76
 
22.10.15
15:32
(35) С данным утверждением я не спорю но как это относится к данному запросу? Все что будет выбрано - будет выбрано по индексам остальное дело процессора. Вы пытаетесь блох поймать. Если просто попугать на будущее, то так и пишите в начале, что вы ударились в философию.
37 sash-ml
 
22.10.15
15:38
(33) да ладно tempDB не существует?
38 MadJhey
 
22.10.15
17:11
(32) Ок. Рассмотрим вторую часть запроса, в первой временной таблице все понятно

ВЫБРАТЬ
    ВР.Товар,
    ВР.Количество КАК Количество,
    ВР.ЕдиницаХранения,
    ВЫРАЗИТЬ(ХозрасчетныйДвиженияССубконто.Сумма / ХозрасчетныйДвиженияССубконто.КоличествоКт КАК ЧИСЛО(10, 2)) КАК ЦенаЗакупки,
    ХозрасчетныйДвиженияССубконто.Сумма КАК СуммаЗакупки,
    ВР.Сумма КАК Сумма,
    ВР.СуммаНДС,
    ВР.Цена КАК Цена
ИЗ
    ВР КАК ВР
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(, , Счет = &Счёт, , ) КАК ХозрасчетныйДвиженияССубконто
        ПО (ХозрасчетныйДвиженияССубконто.СубконтоКт1 = ВР.Товар)
            И (ХозрасчетныйДвиженияССубконто.Регистратор = ВР.Ссылка)

на SQL это будет

exec sp_executesql N'SELECT
T1._Q_000_F_000RRef,
T1._Q_000_F_002,
T1._Q_000_F_003RRef,
CAST((CAST(T2.Fld466_ AS NUMERIC(21, 8)) / T2.Fld468Ct_) AS NUMERIC(10, 2)),
T2.Fld466_,
T1._Q_000_F_004,
T1._Q_000_F_006,
T1._Q_000_F_001
FROM #tt1 T1 WITH(NOLOCK)
LEFT OUTER JOIN (SELECT
T3._RecorderTRef AS RecorderTRef,
T3._RecorderRRef AS RecorderRRef,
T3._Fld466 AS Fld466_,
T3._Fld468Ct AS Fld468Ct_,
T3._ValueCt1_TYPE AS ValueCt1_TYPE,
T3._ValueCt1_RTRef AS ValueCt1_RTRef,
T3._ValueCt1_RRRef AS ValueCt1_RRRef
FROM #tt2 T3 WITH(NOLOCK)) T2
ON ((T2.ValueCt1_TYPE = CASE WHEN T1._Q_000_F_000RRef IS NOT NULL THEN 0x08 END AND T2.ValueCt1_RTRef = CASE WHEN T1._Q_000_F_000RRef IS NOT NULL THEN P1 END AND T2.ValueCt1_RRRef = T1._Q_000_F_000RRef) AND (T2.RecorderTRef = CASE WHEN T1._Q_000_F_005RRef IS NOT NULL THEN @P2 END AND T2.RecorderRRef = T1._Q_000_F_005RRef))',N'P1 varbinary(4),@P2 varbinary(4)',0x00000036,0x000000C1
39 MadJhey
 
22.10.15
17:13
где #tt1  - это ВР,
а #tt2 - это временная таблица с результатом расчета движения по субконто.
40 MadJhey
 
22.10.15
17:14
тут еще куча промежуточных временных таблиц. смухлюю приведу расчет для упрощенного варианта.

Выбрать Первые 11
ХозрасчетныйДвиженияССубконто.Сумма
Из
РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(, , Счет = &Счёт, , ) КАК ХозрасчетныйДвиженияССубконто
      
exec sp_executesql N'SELECT TOP 11
T1.Fld466_
FROM (SELECT
T5._Fld466 AS Fld466_
FROM (SELECT DISTINCT
T3._RecorderTRef AS RecorderTRef,
T3._RecorderRRef AS RecorderRRef,
T3._LineNo AS LineNo_
FROM _AccRg462 T3 WITH(NOLOCK)
WHERE ((T3._AccountDtRRef = P1))
UNION SELECT
T4._RecorderTRef AS RecorderTRef,
T4._RecorderRRef AS RecorderRRef,
T4._LineNo AS LineNo_
FROM _AccRg462 T4 WITH(NOLOCK)
WHERE ((T4._AccountCtRRef = @P2))) T2
INNER JOIN _AccRg462 T5 WITH(NOLOCK)
ON T5._RecorderTRef = T2.RecorderTRef AND T5._RecorderRRef = T2.RecorderRRef AND T5._LineNo = T2.LineNo_) T1',N'P1 varbinary(16),@P2 varbinary(16)',0x9AE320D5E1503F5A4C3421B79A621088,0x9AE320D5E1503F5A4C3421B79A621088
41 MadJhey
 
22.10.15
17:15
если это не вложенные таблицы, то как выглядят вложенные?
42 MadJhey
 
22.10.15
17:17
(41) вложенный запрос ... пардон
43 singlych
 
22.10.15
17:19
Ну все, впредь никаких левых соединений с виртуальными таблицами.
44 H A D G E H O G s
 
22.10.15
17:21
(43) Очень зря.
45 H A D G E H O G s
 
22.10.15
17:21
"любая виртуальная таблица - это вложенный запрос в SQL"

Нет.
46 MadJhey
 
22.10.15
17:25
(45) давай примеры. Хотелось бы конкретики. Пока те запросы, которые парсил, все было вложенными.
47 H A D G E H O G s
 
22.10.15
17:27
(46) Оперативные остатки.
48 MadJhey
 
22.10.15
17:27
Кстати ссылка.ссылка добавляет лишнее соединение.
exec sp_executesql N'SELECT
T1._Fld4956RRef,
T1._Fld4957,
T1._Fld4953,
T1._Fld4952RRef,
T1._Fld4958,
T2._IDRRef,
T1._Fld4960,
T3._IDRRef
FROM _Document193_VT4950 T1 WITH(NOLOCK)
LEFT OUTER JOIN _Document193 T2 WITH(NOLOCK)
ON T1._Document193_IDRRef = T2._IDRRef
LEFT OUTER JOIN _Enum395 T3 WITH(NOLOCK)
ON T1._Fld4959RRef = T3._IDRRef
WHERE (T2._IDRRef IN (@P1))',N'@P1 varbinary(16)',0x837908606E6E76BD11E3BB0E91DABDE9


exec sp_executesql N'SELECT
T1._Fld4956RRef,
T1._Fld4957,
T1._Fld4953,
T1._Fld4952RRef,
T1._Fld4958,
T1._Document193_IDRRef,
T1._Fld4960,
T2._IDRRef
FROM _Document193_VT4950 T1 WITH(NOLOCK)
LEFT OUTER JOIN _Enum395 T2 WITH(NOLOCK)
ON T1._Fld4959RRef = T2._IDRRef
WHERE (T1._Document193_IDRRef IN (@P1))',N'@P1 varbinary(16)',0x837908606E6E76BD11E3BB0E91DABDE9
49 MadJhey
 
22.10.15
17:33
(46)
ВЫБРАТЬ Первые 10
    ОстаткиТоваровОстатки.КоличествоОстаток,
    ОстаткиТоваровОстатки.Товар
ИЗ
    РегистрНакопления.ОстаткиТоваров.Остатки КАК ОстаткиТоваровОстатки


exec sp_executesql N'SELECT TOP 10
T1.Fld21Balance_,
T1.Fld20RRef
FROM (SELECT
T2._Fld20RRef AS Fld20RRef,
CAST(SUM(T2._Fld21) AS NUMERIC(30, 8)) AS Fld21Balance_
FROM _AccumRgT22 T2 WITH(NOLOCK)
WHERE T2._Period = P1
GROUP BY T2._Fld20RRef
HAVING (CAST(SUM(T2._Fld21) AS NUMERIC(30, 8))) <> @P2) T1',N'P1 datetime2(3),@P2 numeric(10)','5999-11-01 00:00:00',0
50 H A D G E H O G s
 
22.10.15
17:46
(49) Да, я ошибся.
51 bolobol
 
22.10.15
18:10
(49) А можно вопрос специалисту по виртуальным таблицам тут задать? Почему следующая конструкция даёт некорректные результаты:

ВЫБРАТЬ
    ОстаткиТоваровОстатки.КоличествоОстаток
ИЗ
    РегистрНакопления.ОстаткиТоваров.Остатки КАК ОстаткиТоваровОстатки
ВНУТРЕННЕЕ СОЕДИНЕНИЕ
РегистрНакопления.ОстаткиТоваров.Остатки КАК ОстаткиТоваровОстатки1
ПО ОстаткиТоваровОстатки.Остаток <> ОстаткиТоваровОстатки1.Остаток

?
52 sash-ml
 
22.10.15
18:16
что значит некорректные результаты, тут практически полное соединение
53 bolobol
 
22.10.15
18:27
(52) Вот-вот, а в результат только одна строка выходит...
54 MadJhey
 
22.10.15
22:00
(51) бред какой то. Цель то какая
55 bolobol
 
23.10.15
11:29
(54) Цель: получить все остатки, где результатов более одного в интересующем разрезе.
56 mistеr
 
23.10.15
14:56
(55) Чего?
57 bolobol
 
23.10.15
15:10
(56) Что "чего"?
58 asady
 
23.10.15
15:11
(57) в (51) реальный запрос?
59 bolobol
 
23.10.15
15:16
(58) О, нет конечно. Там и параметры виртуальные и соединения ПО (ресурс слева меньше нуля, справа больше нуля и наоборот) и равенство субконто1 и организации.

в (51) вопрос озвучен с точки зрения технологии его обработки системой, т.к. кроме одной строки в результат ничего не даёт, там где должно быть всё, что имеет соединение.

Если в выборку добавить из второй таблицы данные (ОстаткиТоваровОстатки1.КоличествоОстаток) - то тогда результат верный. Без выборки данных из второй таблицы - одна случайная строка всегда постоянная...
Программист всегда исправляет последнюю ошибку.