|
v7: Прямые запросы - связь между реквизитами типа "Справочник" и "Справочник.X" | ☑ | ||
---|---|---|---|---|
0
Chai Nic
04.10.13
✎
08:39
|
Как сделать left join с каким-то конкретным справочником, если в основной таблице поле имеет тип "Справочник" (общий)? В документации по 1с++ об этом ни слова, там только про дополнительную типизацию параметров запроса с помощью "~" в этом контексте... пробовал применять "~" при указании условия связи - выдает ошибку.
|
|||
1
ADirks
04.10.13
✎
08:55
|
FROM
... A left join $Справочник.ХХХ Б ON Left(А.Рекв, 4) = $ВидСправочника36.ХХХ AND ХХХ.ID = Right(А.Рекв, 9) |
|||
2
Chai Nic
04.10.13
✎
09:00
|
(1) Спасибо! Только наверное с точки зрения быстродействия это не слишком оптимально будет :( Выражения с получением подстроки в условии связи не дадут применить индекс..
|
|||
3
ADirks
04.10.13
✎
09:05
|
(2) именно так
поэтому мы делаем (там где актуально) искуственный рекв. ид13 с отбором, и триггером его заполняем |
|||
4
ADirks
04.10.13
✎
09:06
|
хотя можно конечно и в ПриЗаписи() написать
ид13 = ТекущийЭлемент(); |
|||
5
Chai Nic
04.10.13
✎
09:48
|
(3) Вот почему 1с так сама не сделала.. Вместо дурацкого составного реквизита могли бы в базе хранить два реквизита - описание типа и собственно ссылку.
|
|||
6
viktor_vv
04.10.13
✎
09:57
|
C Left() есть шанс что будет использован индекс, хотя бы отберет по виду.
|
|||
7
ADirks
04.10.13
✎
10:05
|
(5) не, на самом деле было бы удобнее, чтобы все ИД поля были ид13 - никакой путаницы, и все ИДшники в рамках базы уникальны. Но как обычно - экономим на спичках, просираем сотни нефти.
|
|||
8
Salimbek
04.10.13
✎
10:15
|
left join $Справочник.ХХХ Б ON А.Рекв = $ВидСправочника36.ХХХ+Б.ID
|
|||
9
Mikeware
04.10.13
✎
10:18
|
(5)1с в 1998 и представить в страшном сне не могла, что ее структуру так расковыряют....
Нуралиев же отвечал на просьбу отдать 7.7. в свободное плаванье, что не будет, ибо не дурак делать себе конкурента (а 7.7 с доработками вполне себе на уровне снеговика.) |
|||
10
Mikeware
04.10.13
✎
10:19
|
(7)тогда эти "спички" были нелишние... скажи мне в те годы, что вполне реальна база коммерческой компании в 100Г - я б драться полез...
|
|||
11
ADirks
04.10.13
✎
10:28
|
(10) ну вообще да, всё-таки ДБФ не всякие вольности позволяет.
(8) вот я специально этот вариант не стал приводить, обычно он затратнее. |
|||
12
Chai Nic
04.10.13
✎
10:57
|
(7) Да, наверное так было бы лучше. Правда, по сравнению со способом хранения периодических реквизитов это мелочь. Вот там кошмар полный.. для производственной базы с ценами материалов, нормировкой техопераций, вариантами техпроцесса эта таблица раздувается просто неприлично, доступ к данным при этом значительно замедляется. Что мешало периодические реквизиты конкретного справочника хранить в отдельной таблице? Возможность получить все возможные периодические реквизиты на заданную дату одним запросом, разве что.. а нафига?
|
|||
13
Salimbek
04.10.13
✎
11:01
|
(11) Ну так то возможно. Только (обычно) справочники не очень большие и поиск пролетает за доли секунды. Если же справочник большой... Тогда, типа:
SELECT $ВидСправочника36.ХХХ+Б.ID as ID13, Б.ID as ID (плюс еще какие нужно поля) INTO #tmp FROM $Справочник.ХХХ as Б затем CREATE INDEX idx_id13 (ID13) ну и left join #tmp Б ON А.Рекв = Б.ID13 |
|||
14
Ёпрст
04.10.13
✎
11:02
|
(12) не.. 1сконст это цветочки, вот блоб в дбф это нечто.
|
|||
15
trad
04.10.13
✎
11:05
|
(2),(3) будьте спокойны, в (1) ни один индекс не пострадает.
Там отлично отработает индекс - IDD и в плане скорости совершенно пофиг Б.ID = Right(А.Рекв, 9) или Б.ID36 = А.Рекв за исключением микроскопических долей процента на операцию right |
|||
16
trad
04.10.13
✎
11:06
|
а вот в (8) - вредительство, тут точно индекс работать не будет
|
|||
17
Mikeware
04.10.13
✎
11:09
|
(14) блоб - аналог мемополей.
---- а вообще, интерсно - спустя 15 от создания (при среднем сроке эксплуатации софта 5 лет) мы обсуждаем архитектуру.... |
|||
18
Chai Nic
04.10.13
✎
11:18
|
(17) С блобами вообще непонятно.. FoxPro поддерживал блобы штатно, что мешало воспользоваться их технологией, а не изобретать велосипед?
|
|||
19
Salimbek
04.10.13
✎
11:19
|
(16) Хм, буду знать, почему-то считал что так выгоднее... (ушел в печали)
|
|||
20
viktor_vv
04.10.13
✎
11:20
|
(15) Насчет микроскопической доли на Right() поспорил бы.
Я правда на Журнале проверял по общему реквизиту с отбором. Так плана Select ДокЗаявкаШапка.IDDOC as ДокЗаявка , Ж.Date_Time_IDDOC as ДатаДокОсн From dh4319 as ДокЗаявкаШапка (nolock) Left join _1Sjourn as Ж (nolock) on Left(Ж.sp4304, 4) = ' 3BZ' and ДокЗаявкаШапка.IDDOC = Right(Ж.sp4304,9) Left(Ж.sp4304, 4) = ' 3BZ' - index scan с условием coast 60% ДокЗаявкаШапка.IDDOC = Right(Ж.sp4304,9) - compute scalar стоимость 20%. остальные варианты примерно одинаково отрабатывают, тоько распределение стоимости по операциям меняется. |
|||
21
viktor_vv
04.10.13
✎
11:22
|
(20)+ Хотя если на чистую выполнять, то это пожалуй самый быстрый вариант получается.
|
|||
22
viktor_vv
04.10.13
✎
11:26
|
А такой вариант
Select ДокЗаявкаШапка.IDDOC as ДокЗаявка , Ж.Date_Time_IDDOC as ДатаДокОсн From dh4319 as ДокЗаявкаШапка (nolock) Left join _1Sjourn as Ж (nolock) on -- Left(Ж.sp4304, 4) = ' 3BZ' -- and ДокЗаявкаШапка.IDDOC = Right(Ж.sp4304,9) index scan без условия - 30% compute scalar - 5% зато уже на hash match - 55% |
|||
23
trad
04.10.13
✎
11:30
|
(20) эээ, нет
у тебя же совсем не то что в (1) в (1) написано Б.ID = Right(А.Рекв, 9) а у тебя А.ID = Right(Б.ID,9) |
|||
24
trad
04.10.13
✎
11:32
|
по поводу right.
тратим время на right, зато сравниваем char(9) не тратим время на right, зато сравниваем char(13) хотя, я говорю, не стоит на этом заморачиваться |
|||
25
viktor_vv
04.10.13
✎
11:34
|
(23) Таки да :).
|
|||
26
trad
04.10.13
✎
11:34
|
в (1) не будет никаких index scan
там будет православный index seek в loop join'е |
|||
27
viktor_vv
04.10.13
✎
11:43
|
(26) Нету там index seek.
Select ДокЗаявкаШапка.IDDOC as ДокЗаявка , Ж.Date_Time_IDDOC as ДатаДокОсн From _1Sjourn as Ж (nolock) Left join dh4319 as ДокЗаявкаШапка (nolock) -- Left on Left(Ж.sp4304, 4) = ' 3BZ' and ДокЗаявкаШапка.IDDOC = Right(Ж.sp4304,9) index scan по индексу журнала, причем полный, без условия. Условие используется уже аж в hash match. |
|||
28
viktor_vv
04.10.13
✎
11:46
|
(27)+ Насчет нету, это достаточно условно, конкрентно в приведенном примере, на моих данных.
|
|||
29
Ёпрст
04.10.13
✎
11:47
|
(27) дык (23)
|
|||
30
Джордж1
04.10.13
✎
11:50
|
(12)а ведь есть способ эмулирования периодических реквизитов на регистрах
|
|||
31
trad
04.10.13
✎
11:59
|
(29) ну (27) он привел к виду (1)
|
|||
32
ADirks
04.10.13
✎
12:18
|
Ну прям интересно стало :))
4 варианта: -- 1 select спр.ID FROM регПартииИтоги р left join спрМатериалы спр ON ' 1EH'+спр.ID = р.МПЗ WHERE р.Period = '20130101' -- 2 select спр.ID FROM регПартииИтоги р left join спрМатериалы спр ON left(р.МПЗ, 4)=' 1EH' and спр.ID = Right(р.МПЗ, 9) WHERE р.Period = '20130101' -- 3 select спр.ID FROM регПартииИтоги р left join спрМатериалы спр ON спр.ид13 = р.МПЗ WHERE р.Period = '20130101' -- 4 select спр.ID FROM регПартииИтоги р left join спрМатериалы спр ON спр.ид13 = р.МПЗ WHERE р.Period = '20130101' and left(р.МПЗ, 4)=' 1EH' Самый незатратный - №2. Даже читерский вариант 4 - затратнее. Процентики: 1 - 23 2 - 20 3 - 31 - clustered index scan 4 - 26 - аналогично А вот если в селект-листе вместо ID получать ROW_ID - то №4 выигрывает, потому что начинает использовать индекс VIA, а №2 и №3 одинаковы по времени. Так что, в индекс попасть не всегда так просто как кажется. Надо поправку на ветер и плотность воздуха учитывать! |
|||
33
trad
04.10.13
✎
12:23
|
(27) да, подтверждаю, index scan может быть
Зависит от размера таблицы Б если она небольшая, то seek+loop если большая, то skan+(hash||merge) |
|||
34
trad
04.10.13
✎
12:28
|
(32) 2 и 4 логически же не равны
А во втором убери left(р.МПЗ, 4)=' 1EH' тоже в where |
|||
35
viktor_vv
04.10.13
✎
12:28
|
(33) Да. У меня соотношение количества записей таблица Б к таблице А в районе 10%, это уже достаточно много для seek, поэтому и делает scan и hash.
|
|||
36
ADirks
04.10.13
✎
12:35
|
(34) не-не, я же говорю, что №4 - читерство. Надо же все записи получать, а не только по одному справочнику.
Сравнивать надо 2 и 3 - и тут результаты очень близки, как по времени, так и по использованию индексов - просто индексы разные. |
|||
37
trad
04.10.13
✎
12:36
|
(35) + при этом если его принудить к loop, то выполняется быстрее примерно в 2 раза и количество чтений страниц меньше на порядок (на моих данных)
|
|||
38
viktor_vv
04.10.13
✎
12:40
|
(37) Да я вот тоже замечал, что hash тормозной, хотя его описывают как быстрый, наверное накладные расходы на создание hash-таблиц большие.
|
|||
39
trad
04.10.13
✎
12:45
|
(38) просто для hash нужны обе таблицы в полном составе, т.е. и таблица Б должна быть полностью прочитана перед связыванием,
а для loop "выдергиваются" только записи по условию связывания по мере обхода таблицы А и он (loop) очень подходит при "выдергивании" индекс-сиком |
|||
40
Ёпрст
04.10.13
✎
12:59
|
(39) не напомнишь, tabledoc может управлять РВД на форме ?
|
|||
41
Salimbek
04.10.13
✎
13:05
|
(32) Я дико извиняюсь, но можно попробовать такой вариант, чисто для любопытства:
select спр.ID FROM регПартииИтоги р left join спрМатериалы спр ON left(р.МПЗ, 4)=' 1EH' and ' 1EH'+спр.ID = р.МПЗ WHERE р.Period = '20130101' |
|||
42
trad
04.10.13
✎
13:09
|
(40) не пробовал даже :)
|
|||
43
trad
04.10.13
✎
13:12
|
(42)+ попробовал, не может
|
|||
44
viktor_vv
04.10.13
✎
13:21
|
(41) Попробовал похожий вариант.
Select ДокЗаявкаШапка.IDDOC as ДокЗаявка , Ж.Date_Time_IDDOC as ДатаДокОсн From _1Sjourn as Ж (nolock) Left join dh4319 as ДокЗаявкаШапка (nolock) -- Left on Left(Ж.sp4304, 4) = ' 3BZ' and ' 3BZ'+ДокЗаявкаШапка.IDDOC = Ж.sp4304 по сравнению с ДокЗаявкаШапка.IDDOC = Right(Ж.sp4304,9) уменьшилась стоимость для compute scalar ' 3BZ'+ДокЗаявкаШапка.IDDOC . Оно логично, так как compute scalar для Right(Ж.sp4304,9) выполняется на большей таблице, а для 3BZ'+ДокЗаявкаШапка.IDDOC на меньшей. |
|||
45
ADirks
04.10.13
✎
13:23
|
(41)
-- 1 select М.ROW_ID FROM регПартииИтоги р left join спрМатериалы М ON left(р.МПЗ, 4)=' 1EH' and М.ID = Right(р.МПЗ, 9) WHERE р.Period = '20130101' -- 2 select спр.ID FROM регПартииИтоги р left join спрМатериалы спр ON left(р.МПЗ, 4)=' 1EH' and ' 1EH'+спр.ID = р.МПЗ WHERE р.Period = '20130101' №1 - 49% №2 - 51% разница в основном из-за ' 1EH'+спр.ID - ещё один compute scalar, и дольнейший hash join получается 61% против 59% |
|||
46
viktor_vv
04.10.13
✎
13:29
|
(45) У меня по 50% процентов получились запросы.
|
|||
47
Salimbek
04.10.13
✎
14:16
|
(45) Любопытно, т.е. фактическая стоимость операций практически одинакова, и далее, как указали в (44) выгоднее смотреть, какая из таблиц меньше и в зависимости от этого использовать либо тот либо другой вариант?
|
|||
48
viktor_vv
04.10.13
✎
14:41
|
(47) Не совсем так. У меня получилось перераспределние стоимости между compute scalar и hash match.
Но в итоге запросы оказались по времени одинаковые. При выполнении двух запросов пакетом, у них стоимость каждого в пакете оказалась одинаковая, по 50%. |
|||
49
ADirks
04.10.13
✎
15:00
|
А вот более жизненный вариант - джойнятся все справочники, которые м.б. в измерении
-- 1 select М.ROW_ID, Н.ROW_ID FROM регПартииИтоги р left join спрМатериалы М ON ' 1EH'+М.ID = р.МПЗ left join спрНоменклатура Н ON ' 35L'+Н.ID = р.МПЗ WHERE р.Period = '20130101' -- 2 select М.ROW_ID, Н.ROW_ID FROM регПартииИтоги р left join спрМатериалы М ON left(р.МПЗ, 4)=' 1EH' and М.ID = Right(р.МПЗ, 9) left join спрНоменклатура Н ON left(р.МПЗ, 4)= ' 35L' and Н.ID = Right(р.МПЗ, 9) WHERE р.Period = '20130101' --3 select М.ROW_ID, Н.ROW_ID FROM регПартииИтоги р left join спрМатериалы М ON М.ид13 = р.МПЗ left join спрНоменклатура Н ON Н.ид13 = р.МПЗ WHERE р.Period = '20130101' Процентики 1 - 67% 2 - 17% 3 - 17% для №1 строится сильно другой план, затраты на который сильно больше |
|||
50
ADirks
04.10.13
✎
15:03
|
ой, в №1 забыл условие по left(р.МПЗ, 4)= ' 35L'
так получается 52, 22, 22 |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |