Холиварный мегасрач - 2

  1. 9 г. назад
    10.06.2014 08:15:08 отредактировано andrewks

    Опять три варианта!
    Кто круче ЛефтДжоин, ЮнионОлл, или Временная таблица?!
    (есссно, Контрагент в Таблица1 и Таблица2 встречается только по одному разу)

    1. Левое соединение к подзапросу - здесь в условии подзапроса может быть любое другое условие, не обязательно отбор по Контрагентам

    ВЫБРАТЬ 
       Таблица1.Контрагент как Контрагент,
       Таблица1.Поле как Таб1Поле,
       Подзапрос.Поле как Таб2Поле
    Из Таблица1 как Таблица1
        ЛевоеСоединение (Выбрать 
    							Таблица2.Контрагент, 
    							Таблица2.Поле 
    						ИЗ Таблица2 как Таблица2 
    						ГДЕ 
    						   Таблица2.Контрагент в (&СписокКонтрагентов)) как Подзапрос
        ПО Таблица1.Контрагент = Подзапрос.Контрагент
    ГДЕ Таблица1.Поле2  в (&СписокКонтрагентов)
    

    2. Юнион с группировкой - наверное самый оптимальный вариант

    ВЫБРАТЬ
                  Подзапрос.Контрагент как Контрагент, 
    	МАКСИМУМ(Подзапрос.Таб1Поле) как Таб1Поле,
    	МАКСИМУМ(Подзапрос.Таб2Поле) как Таб2Поле
    ИЗ 
    (
    	ВЫБРАТЬ
                                 Таблица1.Контрагент как Контрагент,
    		Таблица1.Поле как Таб1Поле,
    		NULL как Таб2Поле
    	ИЗ
    	    Таблица1 как Таблица1
    	ГДЕ Таблица1.Контрагент в (&СписокКонтрагентов)
    
    	ОБЪЕДИНИТЬ ВСЕ
    
    	ВЫБРАТЬ
                                Таблица2.Контрагент,
    		NULL,
    		Таблица2.Поле3
    	ИЗ
    	    Таблица2 как Таблица2
    	ГДЕ Таблица2.Контрагент в (&СписокКонтрагентов)
    
    ) как Подзапрос
    ГРУППИРОВАТЬ ПО Подзапрос.Контрагент
    

    3. Временная таблица и левое соединение - самый читабельный

    Выбрать 
    	Таблица2.Контрагент, 
    	Таблица2.Поле 
    ПОМЕСТИТЬ ВремТаблица2
    ИЗ Таблица2 как Таблица2 
    где 
       Таблица2.Контрагент в (&СписокКонтрагентов)
    ;
    
    ВЫБРАТЬ 
       Таблица1.Контрагент как Контрагент,
       Таблица1.Поле как Таб1Поле,
       ВремТаблица2.Поле как Таб2Поле
    Из Таблица1 как Таблица1
        ЛевоеСоединение ВремТаблица2 как ВремТаблица2
        ПО Таблица1.Контрагент = ВремТаблица2.Контрагент
    ГДЕ Таблица1.Поле2  в (&СписокКонтрагентов)
    
    

    З.Ы.: Писал без конструктора, если что простите за синтаксические ошибки

  2. А-а-а! Дурацкий форум порушил всю мою табуляцию! Я сидел, блин, отступы проставлял!

    Ответы: (4)
  3. Свои варианты тоже можно предлагать.

  4. Блеать, по коду нужно отгадать решаемую задачу?

    Ответы: (5)
  5. (1) учись, студент! ©

    Ответы: (6)
  6. 10.06.2014 08:19:47 отредактировано БухиТог

    (3) да нет никакой задачи!

    Я накидал три примера. Предлагаю обсудить достоинства и недостатки каждого метода.

    З.Ы.: Гуру от запросов всяческим калом поливают левое соединение, дескать та таблица что справа (Таблица2) будет перебираться столько раз сколько строк в левой таблице (Таблица1) и я обычно где можно пытаюсь заменить левое соединение юнионом.

    Ответы: (7) (16)
  7. (4) Ух ты! Красота!

  8. (5) и всё-таки, что должен получить запрос?

    Ответы: (8)
  9. (7) р-р-р!!! Да ничего он не должен получить! Абстрактный пример!

    Видишь первый запрос?
    Подзапрос в нём будет работать один раз, или столько раз сколько строк в Таблица1 ?
    Или столько раз сколько строк в Таблица1, удовлетворяющих условию в "ГДЕ" ?

    Ответы: (9) (10)
  10. (8) сначала отработает подзапрос, потом будет сделано соединение с результатом

    Ответы: (11) (39)
  11. БухиТог Да ничего он не должен получить! Абстрактный пример!

    тогда для чего написано:

    Юнион с группировкой - наверное самый оптимальный вариант

    самый оптимальный вариант для чего ?

    Ответы: (12)
  12. (9) я тоже так предполагал.

    а обосновать как то можешь?

    Ответы: (13)
  13. (10) самый оптимальный вариант для чего?

    по нагрузке на сервак например

    Ответы: (15)
  14. (11) ну, могу лишь предложить заглянуть в ТЖ, чтобы увидеть скуль-запрос, в который транслируется данный текст

    Ответы: (40)
  15. 1-й и 3-й запросы - суть одно и то же с разной записью, но в целом я за ВТ

  16. (12) обоснуй

    Ответы: (16)
  17. (15) потому что левое соединение аццкое зло! См. (5)

    Гуру от запросов всяческим калом поливают левое соединение, дескать та таблица что справа (Таблица2) будет перебираться столько раз сколько строк в левой таблице (Таблица1) и я обычно где можно пытаюсь заменить левое соединение юнионом.

    Ответы: (21)
  18. в 1 и 3 запросах имеем две входных таблицы размером N, N x N сопоставлений строк, и на выходе результат размером N

    во 2 запросе имеем имеем две входных таблицы размером N, промежуточную таблицу с числом строк M = 2N, по которой осуществляется группировка с вычислением агрегатных функций, и на выходе результат размером N.

    при группировке и агрегировании нужно, как минимум, произвести сортировку промежуточной таблицы, при этом в зависимости от алгоритма сложность будет от O(M x M) до O(M log M)
    я не гуру запросов, и что-то мне пока не очевидно преимущество. конечно, много ещё зависит от конкретных планов запросов, которые будут построены СУБД.
    но как минимум хотелось бы видеть некие результаты тестирования на реальных данных больших размеров

    Ответы: (18)
  19. (17) делал подсчет количества строк в документах за месяц (порядок сотня тысяч доков). Через левое соединение, а там похоже тупой перебор строк таблицы подзапроса по каждой строке соединяемой, это дико долго, кароче имхается, что на больших и огромных выборках, временная таблица с ИНДЕКСИРОВАТЬ ПО - рулит, а левое соединение - жуткий сакс и отстой (нечто очень плохое).

    Ответы: (19) (21)
  20. (18) понятно, что индекс добавить драйва, но вопрос-то не в этом, т.к. индекс добавит драйва обоим вариантам.

    а есть под рукой тексты запросов, про которые ты упоминаешь?

  21. 3-ий вариант самый православный и единственный который разумно отработает на ВСЕХ СУБД, а вот первый и второй вариант "НА НЕКОТОРЫХ СУБД(не будем показывать пальцем)" могут не родится.

    p.s. Свой вывод пишу по платформе 8.2 релиза 11 года в связке ЗУП на Oracle, эта СУБД убивает(ла) любые вложенные запросы сцуко. Приходилось очень многое переделывать на ВТ.

    Ответы: (22)
  22. (18) во! Почти слово в слово (16)

  23. (20) именно так, вот слова представителей 1С "Типичные причины неоптимальной работы запросов и методы оптимизации"
    Рекомендации

    При написании запросов не следует использовать соединения с подзапросами. Следует соединять друг с другом только объекты метаданных или временные таблицы. Если запрос использует соединения с подзапросами, то его следует переписать с использованием временных таблиц.

    Если запрос содержит соединения с подзапросами, то это может привести к следующим негативным последствиям:
    Крайне медленное выполнение запроса при слабой загрузке серверного оборудования. Замедление запроса может быть очень значительным (до нескольких порядков).
    Нестабильная работа запроса. При некоторых условиях запрос может работать достаточно быстро, при других - очень медленно.
    Значительная разница по времени выполнения запроса на разных СУБД.
    Повышенная чувствительность запроса к актуальности и полноте статистик. Сразу после полного обновления статистик запрос может работать быстро, но через некоторое время опять замедлиться.
    Пример потенциально опасного запроса, использующего соединение с подзапросом:

    ВЫБРАТЬ ...
    ИЗ Документ.РеализацияТоваровУслуг
    ЛЕВОЕ СОЕДИНЕНИЕ (
    ВЫБРАТЬ ИЗ РегистрСведений.Лимиты
    ГДЕ ...
    СГРУППИРОВАТЬ ПО ...
    ) ПО ...

    В данном примере в правой части соединения используется подзапрос, а не объект метаданных. Обратите внимание на то, что в какой части соединения (правой или левой) используется подзапрос - не важно. Точно так же не важно, какого типа соединение указано (ЛЕВОЕ, ПРАВОЕ и т.д.). Во всех случаях такая конструкция является потенциально опасной и должна быть исправлена при помощи временных таблиц.

    Обратите внимание на то, что возможность использования временных таблиц появилась в 1С:Предприятии начиная с версии 8.1. Если вы используете версию 8.0, то для решения проблемы производительности такого запроса следует перейти на 8.1.

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

    Внимание! Не забудьте проиндексировать созданную временную таблицу. В качестве индексных полей следует указать все поля, которые используются в условии соединения.

    Ответы: (42)
  24. Только ВТ, будьте умничками

    Ответы: (24)
  25. (23) а паааачиму только ВТ?
    Я, например, за Юнион!

    Ответы: (25) (26)
  26. (24) Да пусчай будет юнион, но только не вложенным делай, а через ВТшку. И буит счастье на любой СУБДшке !

  27. (24) Юнион хуже ВТ хотя бы потому, что код запроса получается длинным.

  28. Насчет UNION есть еще другая, интересная рекомендация

    Использование логического ИЛИ в секции ГДЕ запроса

    Не следует использовать ИЛИ в секции ГДЕ запроса. Это может привести к тому, что СУБД не сможет использовать индексы таблиц и будет выполнять сканирование, что увеличит время работы запроса и вероянтность возникновения блокировок. Вместо этого следует разбить один запрос на несколько и объединить результаты.
    Например, запрос

    ВЫБРАТЬ Товар.Наименование ИЗ Справочник.Товары КАК Товар ГДЕ Артикул = "001" ИЛИ Артикул = "002"

    следует заменить на запрос

    ВЫБРАТЬ Товар.Наименование ИЗ Справочник.Товары КАК Товар ГДЕ Артикул = "001"
    |ОБЪЕДИНИТЬ ВСЕ
    |ВЫБРАТЬ Товар.Наименование ИЗ Справочник.Товары КАК Товар ГДЕ Артикул = "002"

  29. А вообще, вот есть курс интересный. И вот книга вышла. Курс проходил, понравилось, книгу купить только собираюсь.

    Ответы: (29)
  30. (28) ну и как? Пользуешься агрегатами?

    Ответы: (30)
  31. (29) Нет. Еще не разу не довелось.

  32. Странно, что полдня обсуждали, и никто не заметил, что первый и последний вариант вернут разное, если во второй таблице есть контрагенты, которых нет в первом. В варианте один на самом деле полное соединение, сделанное через жопу левое.
    А по сути вопроса уже сказали, хоть и довольно пространно: временные таблицы удобны тем, что разработчик сам решает, что выбираем вначале, а что потом. По сабжевому примеру разницы-то в общем никакой, а по сложному запросу который обычно через пять-десять промежуточных таблиц работает, без оных весьма вероятен неоптимальный план запроса. Грубо говоря сначала весь справочник перелопатит по какому-то условию, а потом в том что получилось будет трех контрагентов искать, которые в списке, хотя логичней понятно наоборот.

  33. 11.06.2014 05:27:05 отредактировано БухиТог

    если во второй таблице есть контрагенты, которых нет в первом. В варианте один на самом деле полное соединение, сделанное через жопу левое.

    поподробнее, плс
    там конечно в условии "ГДЕ Таблица1.Поле2 в (&СписокКонтрагентов)" косяк, по идее надо было бы "ГДЕ Таблица1.Контрагент в (&СписокКонтрагентов)", но почему ты считаешь что в результат первого запроса попадут Контрагенты из второй таблицы, кторых нет в Таблица1?

    Ответы: (33)
  34. (32) Пардон, в 1 пункте-то левое, чет спросоня показалось что там в условии "ПО" проверка на вхождение в список, а не по Контрагенту связь. Ну да второй вариант все-таки полное. Выбираются все контрагенты которые есть в списке со всеми числами, тогда как в 1 и 3 только те, которые есть в таблице1. Уже поэтому их сравнивать некорректно по производительности. Если подразумевалось все же полное, а не левое, то вариант 2 быстрее прочих, так как полное это сначала левое, потом правое, потом группировка = дольше.

    Ответы: (34)
  35. (33) а если нужно все-таки левое, то наверное правильнее будет так:

    ВЫБРАТЬ 
       Таблица1.Контрагент как Контрагент,
       Таблица1.Поле как Таб1Поле,
       Подзапрос.Поле как Таб2Поле
    Из Таблица1 как Таблица1
        ЛевоеСоединение (Выбрать 
                                Таблица2.Контрагент, 
                                Таблица2.Поле 
                            ИЗ Таблица2 как Таблица2) как Подзапрос
        ПО Таблица1.Контрагент = Подзапрос.Контрагент 
    ГДЕ Таблица1.Контрагент  в (&СписокКонтрагентов)
    

    по первой таблице ты уже проверил, что они в списке, другого там нет. Зачем тебе вторую таблицу сравнивать со списком, если там должны быть только попавшие в первую? Лишнего и так не будет, а на сравнение меньше.

  36. А точнее даже так:

    ВЫБРАТЬ 
       Таблица1.Контрагент как Контрагент,
       Таблица1.Поле как Таб1Поле,
       Подзапрос.Поле как Таб2Поле
    Из Таблица1 как Таблица1
        ЛевоеСоединение Таблица2 как Таблица2
        ПО Таблица1.Контрагент = Таблица2.Контрагент 
    ГДЕ Таблица1.Контрагент  в (&СписокКонтрагентов)
    

    отчего третий вариант вообще теряет смысл :)

    Ответы: (36)
  37. Дядя Васька отчего третий вариант вообще теряет смыс

    вообще сферическая задача, поставленная в сабже, смысла не имеет. вопрос чисто по теории, а не как ещё можно получить данный сферический результат

    Ответы: (37)
  38. (36) Так тут и с теорией-то не выходит, слишком простые запросы. Да еще и теплое с мягким сравнивается. Левое в 1 и 3, с полным в 2. Можно например вот такое сравнить со вторым вариантом:

    ВЫБРАТЬ 
       Таблица1.Контрагент как Контрагент,
       Таблица2..Поле как Таб1Поле,
       Подзапрос.Поле как Таб2Поле
    Из Таблица1 как Таблица1
        ЛевоеСоединение Таблица2 как Таблица2
        ПО Таблица2.Контрагент  в (&СписокКонтрагентов)
    ГДЕ Таблица1.Контрагент  в (&СписокКонтрагентов)
    

    Тут вроде как сопоставимо. А временные таблицы вообще не лезут, слишком простой пример. С ними в любом случае лишнее телодвижение будет.

  39. С временными особо обсуждать-то нечего. Это не только способ сделать его читаемей, но и прямое влияние на план запроса. В каком порядке сам их создаешь, в таком и одинэска будет вынужденна создать, тогда как в сложном запросе с кучей соединений она сделает это на свое усмотрение.

  40. (9) ты не прав...

    Ответы: (42)
  41. (13) А скуль запрос тут при чем?

    Как скулевский запрос влияет7

    Ответы: (42) (53)
  42. Между прочем соединение с подзапросом могут отработать значительно быстрее чем временные таблицы и юнионы.

    Ответы: (42) (43)
  43. (39)обоснуй
    (40)+1 тоже так подумал, но не стал спорить с автором. Будто в скуле не те же самые соединения.
    (41) Фирма 1С против соединений с подзапросом, см. (22)

    Ответы: (45)
  44. (41) Ну что-то мне подсказывает что соединения все равно временные таблицы создают, только неявно. Создавая их сам ты просто сей процесс контролируешь, а если джойнить - все на совести движка. А он понятно не безупречен...

    Ответы: (44)
  45. (43) соединения не создают временные таблицы. Конструкция "поместить в ВТ_Контрагенты" переводится примерно как "Create table #t11" при этом на стороне sql, таблица #t11 физически создается в tempdb. При выполнении соединений, tempdb не используется. Соединения могут выполнятся 3 мя алгоритмами
    1. Хэш соединение http://www.sql.ru/articles/mssql/2007/051103hashjoin.shtml
    2. Соединение вложенных циклов http://www.sql.ru/articles/mssql/2007/051101nestedloopsjoin.shtml
    3. с сортировкой слиянием http://www.sql.ru/articles/mssql/2007/051102mergejoin.shtml
    Оптимизатор сам выбирает какой алгоритм применить, какой алгоритм применен видно из плана выполнения запроса.

    Ответы: (46)
  46. (42)

    1. Порядок выборки данных будет определен при составлении плана запроса на основании ряда параметров системы (индексы, статистика, системные ресурсы и т.д. и т.п.). Если скуль решит, что выгоднее подзапрос сунуть позже, то сунет.
    3. Фирма 1С не против, просто соединение с подзапросом может в некоторых случаях работать непредсказуемо. Что бы добиться предсказуемости и рекомендуют временные таблицы создавать, хотя они могут по времени выполнения серьезно проигрывать.

  47. (44) Временные таблицы хорошо, но не стоит забывать что они кончаются ))) есть предел

    Ответы: (47) (48)
  48. (46) ИМХО перегибаешь. Нельзя утверждать, что временные таблицы всегда размещаются на диске, а выборки подзапросов в оперативке. Скуль сам управляет памятью, стараясь максимально эффективно задействовать оперативку, кэширует. Временные таблицы и выборки подзапросов кушают память одинаково. Сумеет ли скуль запихнуть данные в физическую память или будет свопить зависит от их размера и доступности ресурсов.

  49. (46) Не важно сколько железа на серваках и какого оно качества, адресация временных таблиц сервером 1С конечна.

    Ответы: (49)
  50. (48) Временными таблицы создаются на скуле. Причем здесь сервер 1С? По логике ему безразлично как скуль сварил выборку, с ВТ или без, он получает готовый набор данных.

    Ответы: (50)
  51. (49) Сервер 1С их адресует и на адресацию есть предел.

    Морозов вроде упоминал 30-40 единовременных ВТ

    Ответы: (51)
  52. (50) Такую инфу надо проверять. В реале на такие грабли, даже если это правда, наступить непросто. Надо быть большим фанатом ВТ, чтобы наплодить их столько в одном пакете.

  53. Проверить не сложно.

  54. NcSteel А скуль запрос тут при чем?

    Как скулевский запрос влияет7

    ну, в итоге-то будет выполняться скулевский запрос (или мы принимаем во внимание файловые базы?)

    Ответы: (54)
  55. 18.06.2014 09:18:49 отредактировано NcSteel

    (53) Будет выполняться план запроса. План запроса будет строится на основании многих параметров и текст запроса является одним из этих параметров.

    Ответы: (55)
  56. (54) это понятно. просто ты так интересно выразился, будто пляска идёт от текста запроса на языке 1С. а ведь он лишь транслируется в текст скулевского запроса (и не факт, что он даже внешне будет похож на 1с-вский)

    Ответы: (56)
  57. 18.06.2014 10:07:02 отредактировано БухиТог

    (55) ну уж так и не до узноваемости!
    Понятно что там всякие виртуальные таблицы в подзапросы переделаются, неявные соединения через точку в явные и т.п., но главная то тема, про которую мы говорим - лефт джоин vs юнион vs Времененные таблицы так и останется актуальной для SQL.

или зарегистрируйтесь чтобы ответить!