Имя: Пароль:
1C
1С v8
Оптимальны ли запросы ?
,
0 zak555
 
04.09.11
13:47
ковыряю тут запросы в 8

пусть есть два справочника Сотрудники (иерархический справочник) и подчинённый ему Дети

написать запросы :
1. получить всех сотрудников, имеющих детей
2. -||- без детей


1.

"ВЫБРАТЬ РАЗЛИЧНЫЕ
|    Дети.Владелец.Ссылка
|ИЗ
|    Справочник.Дети КАК Дети"


2.

"ВЫБРАТЬ
|    Сотрудник.Представление
|ИЗ
|    Справочник.Сотрудники КАК Сотрудник
|ГДЕ
|    (НЕ Сотрудник.Ссылка В
|                (ВЫБРАТЬ РАЗЛИЧНЫЕ
|                    Дети.Владелец.Ссылка
|                ИЗ
|                    Справочник.Дети КАК Дети))
|    И Сотрудник.ЭтоГруппа = ЛОЖЬ"
1 kosts
 
04.09.11
13:53
(0) Первый вернет одного сотрудника несколько раз если у него несколько детей
2 zak555
 
04.09.11
13:54
(1) слово РАЗЛИЧНЫЕ не заметно ?
3 kosts
 
04.09.11
13:55
(2) Не заметил
4 zak555
 
04.09.11
13:56
и кстати, как запрос с РАЗЛИЧНЫЕ работает ?
5 zak555
 
04.09.11
13:57
т.е. если бы не было слово РАЗЛИЧНЫЕ то запрос точно обошёл весь подчиненный справочник - пусть будет 1 000 000 элементов
т.е. заметное время
а как справится с этим же но со словом РАЗЛИЧНЫЕ ?
6 kosts
 
04.09.11
13:58
второй запрос

ВЫБРАТЬ
   Сотрудник.Представление
ИЗ
   Справочник.Сотрудники КАК Сотрудник
левое соединение Справочник.Дети КАК Дети по Сотрудник.ссылка = Дети.Владелец.Ссылка
где Дети.Ссылка есть null
7 kosts
 
04.09.11
14:01
(5) что так что так запрос обойдет 1000000 элементов.
Только вернет разное количество.
8 Armando
 
04.09.11
14:01
Что тебя смущает в этих запросах?
9 kosts
 
04.09.11
14:02
В запросах 1С не рекомендуется использовать конструкцию "В", потому что не всегда делаются оптимальные планы.
10 Armando
 
04.09.11
14:04
(9) при этом сами ее активно используют в шаблонах рлс
11 kosts
 
04.09.11
14:07
(10) Историю кто то выкладывал. Что то вроде "Типовые конфигурации 1С не имеют статуса совместимо с 1С"...
12 zak555
 
04.09.11
14:11
(6) ха, про "ЕСТЬ NULL" не знал, как пользоваться



"ВЫБРАТЬ
|    Сотрудник.Представление
|ИЗ
|    Справочник.Сотрудники КАК Сотрудник
|        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Дети КАК Дети
|        ПО Сотрудник.Ссылка = Дети.Владелец.Ссылка
|ГДЕ
|    Дети.Ссылка ЕСТЬ NULL
|    И Сотрудник.ЭтоГруппа = ЛОЖЬ"
13 zak555
 
04.09.11
14:12
(8) оптимальность интересует
14 zak555
 
04.09.11
14:15
мне кажется, что (6) не оптимально

он будет "клеить" всех сотров и все детей.владельцев
15 zak555
 
04.09.11
14:21
что-то типа того, но тут ошибка


ВЫБРАТЬ
   Сотрудник.Представление
ИЗ
   Справочник.Сотрудники КАК Сотрудник

ЛЕВОЕ СОЕДИНЕНИЕ
   (ВЫБРАТЬ РАЗЛИЧНЫЕ
       Дети.Владелец.Ссылка
   ИЗ
       Справочник.Дети КАК Дети) КАК СотрудникиСДетьми

ПО Сотрудник.Ссылка = СотрудникиСДетьми.Ссылка

ГДЕ Сотрудник.Ссылка ЕСТЬ NULL И Сотрудник.ЭтоГруппа = ЛОЖЬ
16 kosts
 
04.09.11
14:28
(15)

ВЫБРАТЬ
   Сотрудник.Представление
ИЗ
   Справочник.Сотрудники КАК Сотрудник
ЛЕВОЕ СОЕДИНЕНИЕ
   (ВЫБРАТЬ РАЗЛИЧНЫЕ
       Дети.Владелец.Ссылка как Ссылка
   ИЗ
       Справочник.Дети КАК Дети) КАК СотрудникиСДетьми
ПО Сотрудник.Ссылка = СотрудникиСДетьми.Ссылка
ГДЕ Сотрудник.Ссылка ЕСТЬ NULL И Сотрудник.ЭтоГруппа = ЛОЖЬ

Но по сути тоже самое что и (12)
17 Alexandr Puzakov
 
04.09.11
15:02
1 и 2 можно получить одним запросом ;)

(16) ахтунг! Зачем соединять с вложенным запросом-то?
18 Dmitrii
 
гуру
04.09.11
15:26
(0) В первом запросе убери точкаСсылка
19 Dmitrii
 
гуру
04.09.11
15:29
+ к (18) да и во всех остальных тоже
20 Dmitrii
 
гуру
04.09.11
15:30
заменить "Сотрудник.ЭтоГруппа = ЛОЖЬ" на "(НЕ Сотрудник.ЭтоГруппа)"
21 Fragster
 
гуру
04.09.11
16:12
второй не оптимальный, надо левое соединение и отбор по null,

да и первый, если придираться - сгруппировать работает быстрее, чем РАЗЛИЧНЫЕ на больших выборках
22 acsent
 
04.09.11
16:21
(21) сгруппировать работает быстрее, чем РАЗЛИЧНЫЕ на больших выборках - врешь
23 ice777
 
04.09.11
16:43
(22) а почему?
24 zak555
 
04.09.11
17:58
(16) запрос не работаеот
25 zak555
 
04.09.11
18:00
(17) > ахтунг! Зачем соединять с вложенным запросом-то?

так это не быстрее ?
26 zak555
 
04.09.11
18:03
переправил (16) получил

"ВЫБРАТЬ
|    Сотрудник.Представление
|ИЗ
|    Справочник.Сотрудники КАК Сотрудник
|        ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ РАЗЛИЧНЫЕ
|            Дети.Владелец КАК Ссылка
|        ИЗ
|            Справочник.Дети КАК Дети) КАК СотрудникиСДетьми
|        ПО Сотрудник.Ссылка = СотрудникиСДетьми.Ссылка
|ГДЕ
|    СотрудникиСДетьми.Ссылка ЕСТЬ NULL
|    И (НЕ Сотрудник.ЭтоГруппа)"
27 zak555
 
04.09.11
18:06
(18) (19) ага

(20) почему ? это быстрее или как ?
28 zak555
 
04.09.11
18:06
(9) > В запросах 1С не рекомендуется использовать конструкцию "В", потому что не всегда делаются оптимальные планы.


где этот написано ?
29 CepeLLlka
 
04.09.11
18:13
(5) Запрос итак тебе обойдёт все элементы.. а потом уже из них выберет только различные..
30 kosts
 
04.09.11
18:25
(28) На ИТС вроде читал
31 Armando
 
04.09.11
18:33
(30) не путаешь с "В ИЕРАРХИИ"?
32 kosts
 
04.09.11
18:36
(31) В ИЕРАРХИИ не заменить соединением, а там было что вместо "В" лучше использовать соединение.
33 Alexandr Puzakov
 
04.09.11
18:50
(25) это намного медленнее. Фирма 1С рекомендует избегать соединений с вложенными запросами и виртуальными таблицами (они тоже являются вложенными запросами, только формируются системой).
34 Alexandr Puzakov
 
04.09.11
18:57
+(33) разумеется, не на каждый случай. Основная причина, по которой стоит отказываться с соединением с вложенными запросами - велик риск ошибки СУБД в построении плана запроса. И самое главное, нужно учитывать прогноз количества элементов, которые будут в соединяемых таблицах: если в обоих таблицах прогнозируется несколько десятков или сотен строк, то можно смело соединять, а если же хотя бы в одной таблице будут десятки тысяч строк, то тады лучше избегать таких соединений...
35 Alexandr Puzakov
 
04.09.11
19:01
Например, если в справочнике сотрудники всего пара сотен элементов, ну и соответственно в справочнике детей тоже несколько сотен элементов, то можно смело соединять их через вложенный запрос, лишние 0.00сколькототам секунд погоды не изменят, а вот если это ИБ в каком-нить большом холдинге, то лучше так не баловаться...
36 zak555
 
04.09.11
19:11
(33) какой тогда вариант ?
37 zak555
 
04.09.11
19:17
*оптимальный
38 Alexandr Puzakov
 
04.09.11
19:20
(36) соединить таблицы

ПО Сотрудники.Ссылка = Дети.Владелец

при таком соединении будут задействованы готовые индексы.
39 zak555
 
04.09.11
19:22
(38) а если бы не в 1с это писать ?
40 Alexandr Puzakov
 
04.09.11
19:23
У справочника-владельца есть индекс

[Ссылка]

у подчиненного справочника есть индексы

[Владелец]+[Код]+[Ссылка]

вот по этим индексам оно и соединится оптимально.
41 Alexandr Puzakov
 
04.09.11
19:23
(39) я х. з. Зависит от СУБД.
42 zak555
 
04.09.11
19:28
(41) sql | mySQL ?
43 zak555
 
04.09.11
19:29
(40) тупо левое соединение владельца с дети.владелец и оттуда смотреть НУЛЛ?
44 Alexandr Puzakov
 
04.09.11
19:35
(43) да!
45 Alexandr Puzakov
 
04.09.11
19:36
(42) ну в рекомендациях как раз описано применительно к SQL Server.
46 zak555
 
04.09.11
19:38
(45) а где они эти рекомендации ?
47 zak555
 
04.09.11
19:39
(44) ладно

пусть владельцев 10 000
у каждого по 50 000 детей

всё равно такой же запрос писать ?
48 Alexandr Puzakov
 
04.09.11
19:39
49 Alexandr Puzakov
 
04.09.11
19:41
(47) желательно. Если очень-очень хочется, то можно и через вложенный запрос, но может получиться не айс...
50 zak555
 
04.09.11
19:42
(48) что нужно для доступа ?
51 Alexandr Puzakov
 
04.09.11
19:43
(50) очевидно, логин и пароль...
52 zak555
 
04.09.11
19:43
(51) ИТС подписки 7
53 Alexandr Puzakov
 
04.09.11
19:47
(52) не-а. Отдельные, как на доступ в партнерскую конференцию. На диске ИТС есть то же самое:

Технологическая поддержка > Методическая поддержка 1С 8 > Технологические вопросы крупных внедрений > типичные причины неоптимальной работы запросов и методы оптимизации
54 Alexandr Puzakov
 
04.09.11
19:49
И все на том же диске стоит почитать:

Технологическая поддержка > Методическая поддержка 1С 8 > Методические рекомендации по конфигурированию > Язык запросов
55 zak555
 
04.09.11
20:17
(54) что-то там про индексы нет
56 Alexandr Puzakov
 
04.09.11
20:44
(55) про индексы отдельная статья.

http://kb.1c.ru/articleView.jsp?id=68
57 zak555
 
04.09.11
20:45
(56) почитаем =)
58 Alexandr Puzakov
 
04.09.11
20:46
На диске ИТС статья "Индексы таблиц базы данных", только вот я не помню, в каком разделе она находится, но можно через поиск найти.
59 zak555
 
04.09.11
20:47
ещё вопрос :

на ИТС есть пример внутреннего соединения :

ВЫБРАТЬ ДокТовары.Номенклатура, Спр.Артикул, ДокТовары.Количество, ДокТовары.Сумма
ИЗ Справочник.Номенклатура КАК Спр
  СОЕДИНЕНИЕ Документ.АвансовыйОтчет.Товары КАК ДокТовары
     ПО Спр.Ссылка = ДокТовары.Номенклатура


это будет тоже самое и с такой же скоростью выполняться, как

ВЫБРАТЬ
   ДокТовары.Номенклатура, Спр.Артикул, ДокТовары.Количество, ДокТовары.Сумма
ИЗ
   Справочник.Номенклатура КАК Спр, Документ.АвансовыйОтчет.Товары КАК ДокТовары
ГДЕ
   Спр.Ссылка = ДокТовары.Номенклатура
60 zak555
 
04.09.11
20:57
это вопрос как бы
61 zak555
 
04.09.11
21:01
результат тот же
а вот скорость как замерить
62 CepeLLlka
 
04.09.11
21:08
ЗАК... слушай.. а есть что-нибудь такое по типа СП только для языка запросов? Не поделишься?
63 zak555
 
04.09.11
21:24
64 ДенисЧ
 
04.09.11
21:29
(59) 1с сделает это одинаковым.
65 CepeLLlka
 
04.09.11
21:48
(63) Так это ж про SQL запросы.. а я про 1С спрашивал же :(
66 cViper
 
04.09.11
22:00
(59) В первом случае будет быстрее.
67 cViper
 
04.09.11
22:01
+(66) Во втором случае он сделает декартово произведение, а потом наложит учловие "ГДЕ".
68 zak555
 
04.09.11
23:00
(64) тогда зачем два варианта ?
69 zak555
 
04.09.11
23:00
(65) тоже самое
70 zak555
 
04.09.11
23:01
(66) обоснование
(67) внутренне соединение это что такое по-твоему ?
я всегда думал, что это декартовое произведение, а потом фильтр
71 cViper
 
04.09.11
23:08
(70) Внутреннее соединение - берутся все значения левого множества у которых есть соответствие из правого множества.
72 cViper
 
04.09.11
23:09
+(71)
Для декартова произведения не надо вообще писать ключевое слово "соединение". Просто в  "ИЗ" указываешь 2 таблицы через запятую и каждой строке левого множество будет соответствовать каждая строка правого множества.
73 cViper
 
04.09.11
23:12
+(72) В SQL есть CROSS JOIN.
74 zak555
 
04.09.11
23:59
(71) да, согласен


Внутренние соединения

Внутренние соединения - самый распространённый тип соединений. Внутреннее соединение просто находит пары строк, которые соединяются и удовлетворяют предикату соединения. Например, показанный ниже запрос использует предикат соединения "S.Cust_Id = C.Cust_Id", позволяющий найти все продажи и сведения о клиенте с одинаковыми значениями Cust_Id:

select * from Sales S inner join Customers C on S.Cust_Id = C.Cust_Id
75 zak555
 
05.09.11
13:01
нужно проверять на данных
надо в БД забить 1 000 000 детей
76 Alexandr Puzakov
 
05.09.11
13:29
(75) что мешает?
77 Axel2009
 
05.09.11
13:36
"ВЫБРАТЬ РАЗЛИЧНЫЕ
|    Дети.Владелец
|ИЗ
|    Справочник.Дети КАК Дети"
самое оптимальное - так. будет проверяться 1 индекс и вывод его. без доп чтений.
а все остальное будет тормозом.
запрос "В" может свалится в "или" и будете иметь реальные тормоза.
78 Axel2009
 
05.09.11
13:38
(67) планы то сравнивал? чтобы такое говорить?
79 Axel2009
 
05.09.11
13:41
(21) различные и сгруппировать - монопенисуальные операции если план смотреть..
80 VVi3ard
 
05.09.11
14:00
По 2рому запросу в данном случае наверное разницы нет так как объемы маленькие но в целом лучше использовать временную таблицу и пакет запроса.

1. Формируем ВТ:  ВТСотрудникиСДетьми, добавляем индекс по "ССылка".

2. К  "Справочник.Сотрудники" левым соединением присоединяем ВТСотрудникиСДетьми в где пишем условие ВТСотрудникиСДетьми.Ссылка ЕСТЬ NULL ну и другие по желанию.
81 Fragster
 
гуру
05.09.11
14:04
(22) при выборке одного поля по индексу - да. иначе - нет
82 VVi3ard
 
05.09.11
14:06
(33) "Это намного медленнее. Фирма 1С рекомендует избегать соединений с вложенными запросами и виртуальными таблицами (они тоже являются вложенными запросами, только формируются системой)".

Ну с Вложенными запросами понятно, на момент выполнения запроса SQL ничего не знает о количестве записей в результате вложенного запроса, и с индексами тоже нет определенности поэтому запрос может выполнятся не оптимально.

А в чем проблема при соединении с ВременымиТаблицами?
83 kuza2000
 
05.09.11
14:15
(0)
  Не совсем корректно поставлено вопрос, поскольку SQL - это декларативный язык, а не процедурный. Понятие эффективности лучше всего относить к плану исполнения запроса в применении к конкретным данным. Один и тот же текст запроса может транслироваться в план огромным числом способов в-зависимости от большого числа факторов. И наоборот - разные запросы могут порождать один и тот же план.

  Пример. Есть два запроса.

  Первый:

ВЫБРАТЬ Таб1.*
ИЗ Таб1 ВНУТРЕННЕЕ СОЕДИНЕНИЕ Таб2 ПО Таб1.Поле = Таб2.Поле

Второй:

ВЫБРАТЬ Таб1.*
ИЗ Таб1
ГДЕ Таб1.Поле В (ВЫБРАТЬ Таб2.Поле ИЗ Таб2)

  Вроде бы разные запросы, но на MS SQL план исполнения обоих у меня получался совершенно одинаков. Не похож, а именно совершенно одинаков. Поэтому, что бы узнать точно, что будет эффективнее - путь только один. Пробовать на конкретных данных и анализировать план исполнения.
 Но общее правило такое - запросы должны быть максимально просты, что бы оптимизатор "понял" их и сгенерировал оптимальный план.
  Отвечая на вопрос - я бы использовал такие запросы:

Первый.

   ВЫБРАТЬ РАЗЛИЧНЫЕ
       Владелец
   ИЗ
       Дети

Второй.

   ВЫБРАТЬ РАЗЛИЧНЫЕ
       Сотрудники.Ссылка
   ИЗ
       Сотрудники
       ЛЕВОЕ СОЕДИНЕНИЕ Дети ПО Сотрудники.Ссылка = Дети.Владелец
   ГДЕ Дети.Владелец ЕСТЬ NULL

В общем, пробуем и смотрим план! :)
84 VVi3ard
 
05.09.11
14:18
Кстати (17) тоже прав может быть в данном случае выгоднее будет сразу левым соединением без ВТ соединить, но если нужно одновременно получать эти данные то пакеты будут оптимальней.
85 kuza2000
 
05.09.11
14:19
+ (83) Во втором нужно, конечно, условие еще на группы поставить
86 kuza2000
 
05.09.11
14:21
(0) Кстати, первый запрос такой и предложен был, только .Ссылка надо убрать, иначе может быть лишнее неявное соединение :)
87 Axel2009
 
05.09.11
14:34
(81) планы в студию где "иначе нет"
88 Axel2009
 
05.09.11
14:35
(83) "  Вроде бы разные запросы, но на MS SQL план исполнения обоих у меня получался совершенно одинаков. Не похож, а именно совершенно одинаков. Поэтому, что бы узнать точно, что будет эффективнее - путь только один. Пробовать на конкретных данных и анализировать план исполнения. "
повезло.
89 VVi3ard
 
05.09.11
14:36
(83) Я вообще не понимаю зачем использовать конструкцию В (Выбрать .... ) всегда надо в этом случае делать внутренее соединение.

Не В(Выбрать ) я ещё могу понять.
90 Fragster
 
гуру
05.09.11
14:37
(89) отбор в параметрах виртуальной таблицы
91 Axel2009
 
05.09.11
14:38
(89) ты не умеешь их готовить.
92 Fragster
 
гуру
05.09.11
14:43
(87) очень просто:
берешь
Выбрать * Из Справочник.Номенклатура, открываешь конструктором, удаляешь поле Ссылка (ну и ТЧ, если есть). 1 вариант - получившегося запроса меряешь с Различные, другой - с Группировать.
У меня получилось с Различные 2.2 секунды, с Группировать - 0.2 на 10к элементов справочника номенклатуры
93 Axel2009
 
05.09.11
14:57
(92) а второй раз с Различные?
94 kuza2000
 
05.09.11
14:58
(77) согласен, даже в таблицу не полезет
95 Fragster
 
гуру
05.09.11
15:05
(93) после нескольких выполнений картина более-менее выровнялась, но все равно:
Название таблицы    Время подзапроса    Количество строк
РАЗЛИЧНЫЕ1    0,5    10 080
СГРУППИРОВАТЬ1    0,485    10 080
РАЗЛИЧНЫЕ2    0,547    10 080
СГРУППИРОВАТЬ2    0,328    10 080
96 Fragster
 
гуру
05.09.11
15:05
разница, очевидно, в пользу Сгруппировать
97 Fragster
 
гуру
05.09.11
15:07
более того, даже если тупо выбирать .Ссылка - все равно ~15% в пользу Сгруппировать
98 Axel2009
 
05.09.11
15:14
(97) не везет твоим различным что могу сказать. у меня в обратку чаще. сгруппировать дольше чем различные..
99 Axel2009
 
05.09.11
15:16
(98)+в общем я сравнивал планы. они идентичны. поэтому время зависит от загрузки сервака и прочее прочее
100 Дукат
 
05.09.11
15:18
100!   =)
101 Stim213
 
05.09.11
15:18
черт((
102 Дукат
 
05.09.11
15:19
(101) шо таки?
103 Fragster
 
гуру
05.09.11
15:20
нда, у меня таки тенденция:


ВЫБРАТЬ
   Таблица.Дата
ПОМЕСТИТЬ Сгруппировать1
ИЗ
   Документ.РеализацияТоваров КАК Таблица

СГРУППИРОВАТЬ ПО
   Таблица.Дата
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
   Таблица.Дата
ПОМЕСТИТЬ Различные1
ИЗ
   Документ.РеализацияТоваров КАК Таблица
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
   Таблица.Дата
ПОМЕСТИТЬ Различные2
ИЗ
   Документ.РеализацияТоваров КАК Таблица
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
   Таблица.Дата
ПОМЕСТИТЬ Сгруппировать2
ИЗ
   Документ.РеализацияТоваров КАК Таблица

СГРУППИРОВАТЬ ПО
   Таблица.Дата


получает
Название таблицы    Время подзапроса    Количество строк
СГРУППИРОВАТЬ1    10,797    1 409 449
РАЗЛИЧНЫЕ1    10,921    1 409 449
РАЗЛИЧНЫЕ2    11,358    1 409 449
СГРУППИРОВАТЬ2    10,948    1 409 449
104 Fragster
 
гуру
05.09.11
15:20
хоть чуть-чуть, но сгруппировать быстрее :)
105 Aprobator
 
05.09.11
15:25
условие можно написать так (НЕ Сотрудник.ЭтоГруппа) - впрочем это дело вкуса.