Подведем итоги. Нарастающие.

Опубликовал Ish_2 в раздел Программирование - Практика программирования

Как одним пакетом запросов получить таблицу просроченных долгов контрагента ?
Подробное иллюстрированное построение пакета запросов.


                                                              Шепоту посвящается.

Возможно  читателю покажется интересным приложение в конце статьи :
Что такое нарастающие итоги ? И зачем они нужны ?

Три подхода или кто прав ?

1. Eugeneer предлагает следующий алгоритм решения задачи получения просроченных долгов контрагентов . Организовать цикл обхода выборки контрагентов ,в каждой итерации которого выполнять "мелкий" запрос к базе и с помощью кодинга получить необходимые данные отчета. Eugeneer имеет весомый аргумент - отчет  http://infostart.ru/public/60670/  ,практическое тестирование которого показало неплохие результаты при размере базы УТ - 13 Гб и количестве контрагентов - более 4 тыс.

2. Ish_2 в дискуссиях с Anig99 и Eugeneer настаивал на том , что лучший вариант с точки зрения быстродействия - это сделать один запрос к базе и за один проход выборки кодингом получить все необходимые для отчета данные . Ish_2 считает весомым аргументом  собственные рассуждения и  умозрительные построения.

3. Anig99  предлагает уместить алгоритм получения всех данных в один пакет запросов. Anig99 имеет весомый аргумент- отчет http://infostart.ru/public/58966/ , который показал хорошее быстродействие при объеме базы 120(!) Гб

В настоящий момент , автор статьи считает , что прав в споре - Anig99. Опуская аргументацию почему Eugeneer и Ish_2 неправы (пожалуй , потянет на отдельную статью о вредности "семерочного" похода при работе с таблицами БД),скажу лишь , что выбранный Anig99  подход , не предполагающий кодинга вовсе  - самый простой и технологичный , при котором мы "отвязываемся" от "слабости" клиента и передаем всю обработку данных  на сервер баз данных. Итак, правильный подход к решению задачи выбран. Осталась мелочь - написать эффективный запрос , обеспечивающий наилучшее быстродействие. Мелочь эту мы и рассмотрим в статье.
     Рассматриваемый ниже вариант построения текста пакета запросов для решения  поставленной задачи представляется автору самым оптимальным  для как небольших, так и очень больших объемов данных (свыше 120-150 ГБ). В демонстрационных целях , для объяснения сути подхода к решению задача несколько упрощена . Несколько упрощен , соответственно , и  предлагаемый к рассмотрению текст пакета запросов . Теперь можно приступить к делу.

Постановка задачи.

Даны две таблицы: 
Таблица «Долги»

 

Контрагент

Долг

ДатаОтсрочки

Компания

  200

     01.11.09

 



Таблица «Обороты»

Контрагент

Период

Рег-р

Сумма

Компания

10.09.09

Накл. 1

        40

Компания

20.09.09

Накл. 2

        60

Компания

31.10.09

Накл. 3

        80

Компания

25.11.09

Накл. 4

      100

 

 

 

 

 

 

Требуется получить таблицу «Просроченные долги»

Контрагент

Период

Рег-р

Сумма

Долг

Просроченный долг

Компания

20.09.09

Накл. 2

        60

       20

                              20

Компания

31.10.09

Накл. 3

        80

        80

                              80

Компания

25.11.09

Накл. 4

      100

      100

                                0

 

 

 

 

 

 

 В выходную таблицу вошли документы на общую сумму равную долгу контрагента (=200).
Алгоритм получения выходной таблицы сводится к нахождению в таблице «Обороты» строки с регистратором «Накл 2»,.
Действительно , сумма долга 200 будет складываться как
Строка «Накл 4» - 100
Строка «Накл 3» - 80
Строка «Накл 2» - 20 , где 20 – это часть значения «Суммы» текущей строки
                                       таблицы «Обороты».
Итак , мы ищем строку в таблице «Обороты», которая является последней в последовательности строк таблицы «Обороты» , «набирающих» в обратном порядке следования строк необходимую сумму долга.

 

 

Frown Отступление для "семерочников".
Не спешите восклицать: " Делов -то ! Пройтись по таблице "Обороты" циклом,  да и дело с концом !" Представьте себе , что во встроенном языке 1с нет оператора цикла .  Возможно, тогда представленный алгоритм не покажется совсем уж нелепым.

 

Описание  алгоритма решения .

I. Получим  суммарные обороты с нарастающими итогами по месяцам из таблицы «Обороты». . Долг контрагента(=200) лежит в интервале 180-280, значит искомый период - сентябрь . Остаток долга для последующего поиска составит 200 – 180 = 20.

В вехней строке таблицы показаны нарастающие итоги оборотов.

0 100 180                                280

       Ноябрь

        Октябрь

         Сентябрь    

         100

           80

               100        


II.  Получим последовательность документов с нарастающими итогами в сентябре. Остаток долга 20 лежит в интервале 0-60 , значит искомая строка  таблицы «Обороты» найдена.
 

0                                                 60                                   100

    Накл.   1  от 20.09.09

       Накл. 1 от 10.09.09

                 60

                 40


III. Скопируем все строки из таблицы «Обороты» с периодом большим или равным 20.09.09 в новую таблицу. Добавим новые колонки «Долг» и «Просроченный долг». Заполним добавленные колонки очевидным образом ,учитывая , что «Долг»  для строки с «Накл. 2» составляет 20, и значение «Даты Отсрочки» - 01.11.09 .

Контрагент

Период

Рег-р

Сумма

Долг

Просроченный долг

Компания

20.09.09

Накл.  2

        60

        20

                              20

Компания

31.10.09

Накл.  3

        80

        80

                              80

Компания

25.11.09

Накл.  4

      100

      100

                                0

 

 

 

 

 

Frown Отступление для "семерочников".
Обратите внимание на то, что с точки зрения здравого ("семерочного") смысла мы сделали немыслимое : вместо очевидного перебора строк в таблице "Обороты"  просуммировали по месяцам всю таблицу. Поехали в Москву через Владивосток ? - Смотри приложение в конце статьи.

 

В демонстрационном примере мы рассматривали лишь два вида интервала для поиска Месяц-документ. В реальных же задачах, когда очень большая таблица "Обороты" имеет строки  с высокой плотностью по времени (розничные продажи по дисконтным картам , как у пользователя Anig99) количество видов интервалов для поиска должно быть увеличено, например Год - квартал - месяц - декада - день - документ.

 

 

 

Текст пакета запросов

 

Рассмотрим текст пакета запросов из отчета "ПросроченныйДолг", содержащегося в демонстрационной конфигурации "ПросроченныйДолг.dt". Таблицы "Долги"и "Обороты" реализованы как справочники . Сделано допущение,  что поле "Период" в справочнике "Обороты" содержит только уникальные значения. 

 


1. Найдем обороты по месяцам

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

  Временная таблица "ОборотыПоМесяцам"

Контрагент

НачПериода

КонПериода

Сумма

Компания

01.09.09

30.09.09

      100

Компания

01.10.09

31.10.09 

        80

Компания

01.11.09

30.11.09

      100

 

 

 

 


2.
Получим нарастающие итоги для "ОборотыПоМесяцам".

ВЫБРАТЬ
        ОборотыПоМесяцам.Контрагент,
        ОборотыПоМесяцам.НачПериода,
        ОборотыПоМесяцам.КонПериода,
        ОборотыПоМесяцам.Сумма,
        СУММА(ОборотыПоМесяцамКопия.Сумма) КАК СуммаПосле,
        СУММА(ОборотыПоМесяцамКопия.Сумма) - ОборотыПоМесяцам.Сумма КАК СуммаДо
ПОМЕСТИТЬ ОборотыПоМесяцамНарастающие
ИЗ
        ОборотыПоМесяцам КАК ОборотыПоМесяцам
  ВНУТРЕННЕЕ СОЕДИНЕНИЕ ОборотыПоМесяцам КАК ОборотыПоМесяцамКопия
  ПО    ОборотыПоМесяцам.Контрагент   =  ОборотыПоМесяцамКопия.Контрагент
   И      ОборотыПоМесяцам.НачПериода <= ОборотыПоМесяцамКопия.НачПериода
СГРУППИРОВАТЬ ПО
        ОборотыПоМесяцам.НачПериода,
        ОборотыПоМесяцам.КонПериода,
        ОборотыПоМесяцам.Контрагент,
        ОборотыПоМесяцам.Сумма
;

 Временная таблица "ОборотыПоМесяцамнНарастающие"

Контрагент

НачПериода

КонПериода

Сумма

 СуммаДо   СуммаПосле  

Компания

01.09.09

30.09.09

      100

        180              280

Компания

01.10.09

31.10.09 

        80

        100              180

Компания

01.11.09

30.11.09

      100

           0              100

 

 

 

 



3.
 Найдем строку, интервал которой от "СуммаДо " до "СуммаПосле" содержит в себе значение долга (=200)
 , используя внутренне соединение таблиц "Долги" и "ОборотыПоМесяцамНарастающие".

ВЫБРАТЬ
        Долги.Контрагент,
        Долги.Долг,
        Долги.ДатаОтсрочки,
        ОборотыПоМесНарастающие.НачПериода,
        ОборотыПоМесНарастающие.КонПериода,
        Долги.Долг - ОборотыПоМесНарастающие.СуммаДо КАК ОстатокДолга
ПОМЕСТИТЬ ДолгиПоВыбраннымМесяцам
ИЗ
        Справочник.Долги КАК Долги
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ОборотыПоМесяцамНарастающие КАК ОборотыПоМесНарастающие
        ПО Долги.Контрагент = ОборотыПоМесНарастающие.Контрагент
        И Долги.Долг > ОборотыПоМесНарастающие.СуммаДо
        И Долги.Долг <= ОборотыПоМесНарастающие.СуммаПосле
;

 Временная таблица "ДолгиПовыбраннымМесяцам"

Контрагент

НачПериода

КонПериода

  Долг

 ДатаОтсрочки   ОстатокДолга 

Компания

01.09.09

30.09.09

     200

     01.11.09              20

 

 

 

4.  Выберем из таблицы "Обороты" документы только за указанный период    

ВЫБРАТЬ
        Обороты.Контрагент,
        Обороты.Документ,
        Обороты.Период,
        ДолгиПоВыбМесяцам.Долг,
        ДолгиПоВыбМесяцам.ОстатокДолга,
        Обороты.Сумма,
        ДолгиПоВыбМесяцам.ДатаОтсрочки
ПОМЕСТИТЬ ДвиженияПоВыбраннымМесяцам
ИЗ
        Справочник.Обороты КАК Обороты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ДолгиПоВыбраннымМесяцам КАК ДолгиПоВыбМесяцам
       ПО Обороты.Контрагент = ДолгиПоВыбМесяцам.Контрагент
       И Обороты.Период >= ДолгиПоВыбМесяцам.НачПериода
       И Обороты.Период <= ДолгиПоВыбМесяцам.КонПериода

;

 Временная таблица "ДвиженияПоВыбраннымМесяцам"

Контрагент

Период

Рег-р

Сумма

Долг

ОстатокДолга

ДатаОтсрочки

Компания

10.09.09

Накл  1

        40

   200

         20

01.11.09

Компания

20.10.09

Накл. 2

        60

   200

         20      

01.11.09

 

 



5.
Получим нарастающие итоги по документам   

ВЫБРАТЬ
       ДвиженияПоВыбМесяцам.Контрагент,
       ДвиженияПоВыбМесяцам.Документ,
       ДвиженияПоВыбМесяцам.Период,
       ДвиженияПоВыбМесяцам.Сумма,
       СУММА(ДвиженияПоВыбМесяцамКопия.Сумма) КАК СуммаПосле,
       СУММА(ДвиженияПоВыбМесяцамКопия.Сумма) - ДвиженияПоВыбМесяцам.Сумма КАК СуммаДо,
       ДвиженияПоВыбМесяцам.ОстатокДолга,
       ДвиженияПоВыбМесяцам.ДатаОтсрочки
ПОМЕСТИТЬ ДвиженияПредварительные
ИЗ
       ДвиженияПоВыбраннымМесяцам КАК ДвиженияПоВыбМесяцам
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ДвиженияПоВыбраннымМесяцам КАК ДвиженияПоВыбМесяцамКопия
       ПО ДвиженияПоВыбМесяцам.Контрагент = ДвиженияПоВыбМесяцамКопия.Контрагент
       И ДвиженияПоВыбМесяцам.Период <= ДвиженияПоВыбМесяцамКопия.Период
СГРУППИРОВАТЬ ПО
       ДвиженияПоВыбМесяцам.Контрагент,
       ДвиженияПоВыбМесяцам.Документ,
       ДвиженияПоВыбМесяцам.Период,
       ДвиженияПоВыбМесяцам.Сумма,
       ДвиженияПоВыбМесяцам.ОстатокДолга,
       ДвиженияПоВыбМесяцам.ДатаОтсрочки

;

   Временная таблица "ДвиженияПредварительные "

Контрагент

Период

....

ОстатокДолга

СуммаДо

СуммаПосле

Компания

10.09.09

....

        20

        60 

      100

Компания

20.10.09

....

        20

        0

       60

 

 




6.
По "ОстаткуДолга" =20 определим единственную строку и выведем ее в таблицу "ДвиженияОкончательные" 

ВЫБРАТЬ
       ДвиженияПредв.Контрагент,
       ДвиженияПредв.Документ,
       ДвиженияПредв.Период,
       ДвиженияПредв.ОстатокДолга - ДвиженияПредв.СуммаДо КАК СуммаДолга,
       ДвиженияПредв.Сумма,
       ДвиженияПредв.ДатаОтсрочки
ПОМЕСТИТЬ ДвиженияОкончательные
ИЗ
       ДвиженияПредварительные КАК ДвиженияПредв
ГДЕ
       ДвиженияПредв.ОстатокДолга > ДвиженияПредв.СуммаДо
       И ДвиженияПредв.ОстатокДолга <= ДвиженияПредв.СуммаПосле
;

  Временная таблица "ДвиженияОкончательные"

Контрагент

Период

....

ОстатокДолга

СуммаДо

СуммаПосле

Компания

20.10.09

....

        20

        0

       60

 

 

 

 

7. Используя таблицу "ДвиженияОкончательные" и внутреннее соединение с исходной таблицей "Обороты" получим выходную таблицу запроса.

ВЫБРАТЬ
       Обороты.Контрагент,
       Обороты.Период,
       Обороты.Документ,
       Обороты.Сумма,
       ВЫБОР
       КОГДА Обороты.Документ = ДвиженияОконч.Документ
                  ТОГДА ДвиженияОконч.СуммаДолга
                   ИНАЧЕ Обороты.Сумма
        КОНЕЦ КАК СуммаДолга,
        ///
        ВЫБОР
        КОГДА Обороты.Период < ДвиженияОконч.ДатаОтсрочки
                    ТОГДА ВЫБОР
                                 КОГДА Обороты.Документ = ДвиженияОконч.Документ
                                              ТОГДА ДвиженияОконч.СуммаДолга
                                              ИНАЧЕ Обороты.Сумма
                                 КОНЕЦ
                    ИНАЧЕ 0
        КОНЕЦ КАК СуммаПросроченногоДолга
ИЗ
        Справочник.Обороты КАК Обороты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ДвиженияОкончательные КАК ДвиженияОконч
        ПО Обороты.Контрагент = ДвиженияОконч.Контрагент
        И Обороты.Период >= ДвиженияОконч.Период

Выходная таблица "ПросроченныеДолги"

Контрагент

Период

Рег-р

Сумма

Долг

Просроченный долг

Компания

20.09.09

Накл.  2

        60

        20

                              20

Компания

31.10.09

Накл.  3

        80

        80

                              80

Компания

25.11.09

Накл.  4

      100

      100

                                0

 

 

 

 


 В прикрепленном к статье  файле "ПросроченныйДолг.dt"(26Кб)  находится небольшая демонстрационная конфигурация,содержащая  :

  • справочники "Контрагенты","Долги","Обороты".
  • отчет "ПросроченныйДолг".

 После запуска конфигурации см. Рисунок ниже :

 

Приложение .
Что такое нарастающие итоги ? И зачем они нужны ?

Дана таблица с именем  «Таблица» наших месячных оборотов :

        Месяц

         Оборот

Сентябрь

            100

Октябрь

              80

Ноябрь

            100

 

Вопрос : В каком месяце мы достигли суммарного оборота 200 ,начиная с сентября  ?
               
Решение.

Представим , что  у нас в языке 1с нет оператора цикла и «в лоб» перебрать строки таблицы мы не можем. Но у нас есть язык запросов.
Вначале сделаем «ненужный» вспомогательный запрос , проясняющий суть соединения по неравенству . Таблица "Таблица" соединяется "сама с собой".


Выбрать Т1.Месяц , Т1.Оборот, Т2.месяц,Т2.Оборот
ИЗ Таблица как Т1
ВнутреннееСоединение Таблица как Т2
по Т1.Месяц >=Т2.Месяц

 

Т1Месяц

  Т1Оборот

  Т2Месяц

   Т2Оборот

Сентябрь

      100

  Сентябрь

        100

Октябрь

        80

  Сентябрь

        100

Октябрь

        80

  Октябрь

          80

Ноябрь

       100

   Сентябрь

        100

Ноябрь

       100

   Октябрь

          80

Ноябрь

       100

   Ноябрь

        100


Уберем из полей выборки лишние поля и сгруппируем по Т1Месяц с суммой поля Т2Оборот

 

Выбрать Т1.Месяц , Т1.Оборот, Сумма(Т2.Оборот) как СуммаПосле // так вот назвал
ИЗ Таблица как Т1
ВнутреннееСоединение Таблица как Т2
по Т1.Месяц >=Т2.Месяц
Сгруппировать ПО Т1.Месяц , Т1.Оборот

 

Т1Месяц

  Т1Оборот

   СуммаПосле

Сентябрь

       100

         100

Октябрь

         80

         180

Ноябрь

       100

         280


Но этого мало , в каждой строке нужно иметь интервал СуммаДо и СуммаПосле.
Поэтому перепишем запрос :


Выбрать Т1.Месяц , Т1.Оборот, Сумма(Т2.Оборот) как СуммаПосле ,
Сумма(Т2.Оборот) – Т1.Оборот как СуммаДо
ИЗ Таблица как Т1
ВнутреннееСоединение Таблица как Т2
по Т1.Месяц >=Т2.Месяц
Сгруппировать ПО Т1.Месяц , Т1.Оборот



Т1Месяц

  Т1Оборот

   СуммаДо

   СуммаПосле

Сентябрь

       100

               0

         100

Октябрь

         80

           100

         180

Ноябрь

       100

           180

         280


Теперь нужно определить в какой строке  выполняется двойное неравенство
СуммаДо <= 200 <= CуммаПосле. Или , другими словами, в каком месяце мы достигли оборота со значением 200.

Для этого поместим результат первого запроса во временную таблицу Итоги и приведем весь  пакетный запрос решения :


Выбрать Т1.Месяц , Т1.Оборот, Сумма(Т2.Оборот) как СуммаПосле ,
Сумма(Т2.Оборот) – Т1.Оборот как СуммаДо
ПОМЕСТИТЬ  Итоги
ИЗ Таблица как Т1
ВнутреннееСоединение Таблица как Т2
по Т1.Месяц >=Т2.Месяц
Сгруппировать ПО Т1.Месяц , Т1.Оборот
;
Выбрать Итоги.Т1Месяц,Итоги.Т1Оборот,Итоги.СуммаДо , Итоги.СуммаПосле  
ИЗ Итоги как Итоги
ГДЕ  200 >Итоги.СуммаДо и 200 <=Итогм.СуммаПосле

 

Выходная таблица решения :

Т1Месяц

  Т1Оборот

   СуммаДо

   СуммаПосле

Ноябрь

       100

           180

         280

 

Вывод : нарастающие итоги (значения колонок СуммаДо и СуммаПосле, задающих определенный интервал) нужны в контексте темы статьи для поиска некоторого определенного значения (Оборот = 200).


Примечание : Представим, что исходная таблица "Таблица" имеет миллионы записей . Тогда какого размера достигнет таблица в результате соединения "сама с собой" ( первый запрос  в приложении) ?
Поэтому нарастающие итоги применять нужно для таблиц ограниченного
размера. В этом весь смысл приведенного в статье алгоритма :
нарастающие итоги применяются сначала для поиска в небольшой таблице месячных итогов , затем "вырезается" интервал в таблице "Обороты" и в этом небольшом месячном интервале снова используются нарастающие итоги для поиска нужного значения оборотов.

 

 

Файлы

Наименование Файл Версия Размер Кол. Скачив.
-
.dt 26,43Kb
01.02.10
283
.dt 26,43Kb 283 Бесплатно

См. также

Лучшие комментарии

90. Александр Медведев 01.12.2009 23:50
(89) Шепот... родной город обязывает... ничего ровного. Если завод, то большего города, если гостиница, то самая бесполезная и высокая в городе, если легковушка, то меньше всех...
Магия, не магия, но из малого произрастает большое.... Современные компьтеры расхолаживают программистов позволяя не задумаваться об оптимизации кода и экономии памяти. В результате получаем расчет себестоимости и корректировку стоимости списания по 6 часов... Перешли для получения нового функционала и получения аналитики - но плата за это - длительность не очень сложных расчетов. Вот проблема на самом деле.
Ответили: (93) (91)
# Ответить
82. Александр Медведев 29.11.2009 10:10
(82) Никуда я не увожу, я просто сокращаю свой пост за счет емкого понятия на уровне 1го курса института. Все рассуждения Eugeneer можно свести именно к Бритве Оккама - не плодить сущностей без надобности или усложнять сверх необходимости. Ключевые слова здесь "надобности" и "необходимости". Кроме того, он абсолютизирует свой опыт и считает, что проблемы больших объемов данных надуманны. Мой пост относился именно к нему, а не к тебе, Шепот.
С тобой всё по другому. Я никак не могу понять, что тебе надо. То ты просишь раскрыть механику оптимизатора запросов SQL - а это теория, т.к. для каждой базы всё будет по-разному. То ты заявляешь, что тебе нужна конкретика - покажите запрос. То ты пишешь пост в стиле "дао программирования". И всех обвиняешь в увиливании...Никто с темы слезть не пытается. Просто люди по-разному воспринимают проблему: кто-то конкретно запрос на дебиторку, кто-то запрос с нарастающими итогами, кто-то преимущества разных вариантов сочетания запросов и кода, а кто-то вообще не видит проблемы. Одно твое желание я знаю точно - расшевелить болото.
Ответили: (83) (82)
+ 1 [ larisab; ]
# Ответить
84. I_G_O_R (файл скачал) 29.11.2009 12:14
ШёПоТ провоцирует,не слушайте(точнее не читайте) его, он любитель поспорить.
# Ответить
6. Шёпот теней 25.11.2009 16:55
скажите пожалуйста ?

ножом - удобно резать ...
топором - удобно колоть ...
молотком - удобно забивать ...

ключевое слово "удобно" ... хотя конечно можно-с и молотком - резать или колоть ...

... 1С поставило во главу угла запросы ... понятно SQL он и есть SQL ...

... но лично я запросами получаю максимально приближенные таблицы - только то, что Запрос делает быстро ...

а вот ТАКИЕ вещи просто делаю в "результатах" ... как и много другое ... потому, что:
... 1. я не такой спец в запросах ...
... 2. и есть вещи для которых данный язык (запросов) просто не приспособлен - елементарно "сцепить" тестовые строки ...

... вотТАКОЕестьМНЕНИЕ ...
Ответили: (10) (7)
+ 1 [ hogik; ]
# Ответить
92. I_G_O_R (файл скачал) 02.12.2009 00:06
скорую вызывайте :o
# Ответить

Комментарии

1. Ish_2 24.11.2009 14:06
Три "никаких" использовались автором при написании пакета запросов :

1. Никаких вложенных запросов.
Представленный пакет предствляет собой совокупность последовательно получаемых простых временных таблиц.
2. Никаких выражений в условиях соединения .
Применение операторов и выражеий в условиях соединения повышает время исполнения запроса.
3. Никаких сложных выражений в полях выборки .
В частности, оператор ВЫБОР применен лишь для двух полей в последнем запросе пакета .
Ответили: (5) (2)
# Ответить
2. Ish_2 24.11.2009 14:29
Особую благодарность хочу выразить Anig99 , стойкостью своей в теме
http://infostart.ru/public/58966/?PAGEN_1=2
вынудившего автора написать эту статью.

Подход Anig99 к решению этой задачи , заключающийся в том , что весь алгоритм должен умещаться в один пакет запросов и не содержать кодинга , представляется автору глубоко верным.
Такое же глубокое ,но уже несогласие, автор выражает по поводу алгоритма решения и техники исполнения в вышеназванной теме Anig99 . См (1).
Ответили: (5)
# Ответить
3. anig99 25.11.2009 13:38
много букв (: но, таки, плюс.
Ответили: (5) (4)
# Ответить
4. Арчибальд 25.11.2009 13:43
(3) А мне как раз буквы понравились :)
# Ответить
5. Ish_2 25.11.2009 14:18
(3) Саша, а где зл-лоба ? Обижаешь...
Ну ничего .. Сейчас попробуем.
Пост (2) во второй части означает отвержение твоего алгоритма решения - раз ! осуждение техники исполнения в твоей разработке с посылом к (1) - два ! Забирай плюс назад !
# Ответить
6. Шёпот теней 25.11.2009 16:55
скажите пожалуйста ?

ножом - удобно резать ...
топором - удобно колоть ...
молотком - удобно забивать ...

ключевое слово "удобно" ... хотя конечно можно-с и молотком - резать или колоть ...

... 1С поставило во главу угла запросы ... понятно SQL он и есть SQL ...

... но лично я запросами получаю максимально приближенные таблицы - только то, что Запрос делает быстро ...

а вот ТАКИЕ вещи просто делаю в "результатах" ... как и много другое ... потому, что:
... 1. я не такой спец в запросах ...
... 2. и есть вещи для которых данный язык (запросов) просто не приспособлен - елементарно "сцепить" тестовые строки ...

... вотТАКОЕестьМНЕНИЕ ...
Ответили: (10) (7)
+ 1 [ hogik; ]
# Ответить
7. Ish_2 25.11.2009 17:45
(6) Согласен, что ножом только режут, топором колят.
Цель этой статьи как раз и показать на конкретном примере ,
что вырежешь ножом - не вырубишь топором.

Привычные топорные "семерочные" алгоритмы в "восьмерке" будут плохо работать или не работать вовсе на базах 100 -200 Гб.
И правильнее писать такие отчеты ,которые будут работать на любых базах, маленьких или больших, без приписок вроде : "Ой , не для всех баз."

Конкретный пример : Anig99 занялся оптимизацией отчета и перешел к варианту "один запрос" не от хорошей жизни, а потому что вывод первоначально сделанного "обычного" отчета занимал более 30 мин.
# Ответить
8. artbear 25.11.2009 17:47
(0) Опять не выставляешь индексы для временных таблиц для тех полей, что используются в условиях соединений.
Совсем не гуд.
Скулевский оптимизатор может не все понять правильно :)
Укажи ему явно индексируемые поля для исключения неоднозначности.
Ответили: (97) (94) (127)
# Ответить
9. artbear 25.11.2009 17:56
(0) Из условия задачи нифига не понял, как из первых 2 таблиц вообще можно получить итоговую таблицу :)
Откуда взялись долги и соответственно просроченные долги для накл.2 и 3 ?
Что такое дата отсрочки? и почему она = 01.11?

или ты что-то в описании пропустил, или условия неточны?
Ответили: (14)
# Ответить
10. Ish_2 25.11.2009 17:57
(6) Продолжим. Ведь почему неправ Ish_2 - в своем предложении сделать один запрос и за один проход выборки получит необходимую таблицу ?
Симпатично , вроде.
А выборка в базе 200Гб может быть настолько большой , что сделает невозможной дальнейшую обработку и выгрузку данных с сервера на клиента. Это раз.
Для больших объемов данных такая переброска данных с сервера на клиента тоже затратна. Это два.

Поэтому нужно стремиться как можно плотнее использовать запросы
и всю обработку выносить на сервер Бд.
Клиент же должен получать готовые выходные данные , небольшие по объему.
Из этой идеологии и вытекает другое построение алгоритмов , так нелюбимое в среде 1сников.
# Ответить
11. artbear 25.11.2009 18:00
(9+) Да, под конец рабочего дня сложновато думать :)
Условия понял, таблицы связал, ТЗ уяснил.
Сами запросы буду анализировать завтра.
# Ответить
12. artbear 25.11.2009 18:07
(0) Изучаю условия и обоснования дальше.
Вопрос - нафига нам нужны лишние выборки и ограничения по месяцам/периодам ?
Ведь в условии об этом нигде не сказано, нужно получить выходную таблицу, в которой нет никаких месяцев :)
# Ответить
13. artbear 25.11.2009 18:15
(12+) Или все-таки ограничение по периодам используются для оптимизации работы запроса?
Если так, предлагаю в описании это каким-то образом обозначить.
Иначе сторонний/новый наблюдатель/тестер, не читавший всю дискуссию, в роли которого я сейчас пытаюсь выступить :) , может не понять данной схемы :)
Ответили: (15)
# Ответить
14. Ish_2 25.11.2009 18:18
(9) Нет , не согласен.

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

ДатаОтсрочки - это дата , которой все суммы документов с более ранней датой считаются просроченным долгом. Обычно в начальных условиях указывается количество дней отсрочки платежа. Я пошел на упрощение и задал в начальных условиях ДатуОтсрочки.
Показывать реальный запрос в статье вряд ли нужно.
Текст запроса и так для статьи слишком велик . Мне не удалось его упростить и сжать сильнее.
# Ответить
15. Ish_2 25.11.2009 18:32
(13) Конечно , в выходной таблице никаких меСяцев нет.
Выбор периода "месяц"- это на вкус разработчика.
У меня вначале демонстрационного запроса находятся суммарные итоги по месяцам (как из один из возможных вариантов).

А у Саши Anig99 вначале запроса находятся суммарные итоги - по дням, потом по месяцам, потом по годам.
Я мог сделать также , но для демонстрации принципа алгоритма показалось достаточным обойтись "МЕСЯЦАМИ".
Ответили: (17)
# Ответить
16. anig99 25.11.2009 19:40
У меня всё ещё ремонт... надо сесть вдумчиво почитать. У меня не получается хорошая критика, пока внимательно не прочту.
Плюс за многое чего стоит. Тем более за спор со мной.
Ответили: (18)
+ 1 [ Ish_2; ]
# Ответить
17. Шёпот теней 25.11.2009 19:40
(15) ... смЕЕЕшно-с ... как только ты ставишь период месяц (разбивка отчёта по месяцам) да ещЁ с такими-то обЪёмами данными в 200 ГБ - у тебя встанет ВСЁ ...

гарантирую, что запросы по частям + ТЗ сделает всЁ гОООраздо быстрее ... проверял ! и делаю именно тАк ...

... что-то не тАк в датскомИСХ_2королевстве ... что-то не договариваем-с... да-сссс...

... нет ужжж ... каждыму инструмент своЁ предназначение - ...

... а если говорить про модное СКД - дык это и есть Запрос+ТаблицаЗначение ...

... вот ...
Ответили: (19) (127)
+ 1 [ hogik; ]
# Ответить
18. Ish_2 25.11.2009 19:44
(16) За фразу :
Плюс за многое чего стоит. Тем более за спор со мной. - Браво !

Заканчивай ремонт и мы обсудим чем твой алгоритм отличается от моего.
# Ответить
19. Ish_2 25.11.2009 20:13
(17) Не-а . Не встанет на 200Гб .
Месячные итоги хранятся отдельно в базе . И обращение будет не ко всей базе , а к месячным итогам. Наоборот - все полетит.

Гарантировать не спеши . Ох , не спеши.
Я ведь нигде не утверждал : запрос +ТЗ медленней .
Я говорил о том , что один пакет запросов - оптимальнее для разных режимов работы , разных размеров баз, для разных по силе "клиентов" и т.д.
Вот чем хорошо перекладывать всю обработку на сервер.

При запросе ты ведь не знаешь за какой период по конретному клиенту нужно делать запрос (может у него есть неоплаченные накладные составляющие текущий долг аж 5 лет назад). Тебе придется или делать один сумашедший запрос по всем клиентам за весь период и твоя любая "клиентская машина" захлебнется. Или же делать несколько запросов по частям выбирая весь период. Что снижает быстродействие.

Время исполнения конкретного алгоритма зависит слишком от многого.

Вот мы встретились с тобой . То , да сё...
Пошли , конечно, прежде всего тестировать и сравнивать быстрдействие твоего метода и моего . И допустим , запрос+ТЗ сработал быстрее.
Может быть такое ? Может.
И ты крикнешь : Ага !!!! С тебя бутылка !
Я вспомню о делах , приму озабоченный вид и по -еврейски (прости, Аркадий) улизну.

И буду прав.Потому что запрос "всё в одном" быстрее не ВСЕГДА. , а в среднем.
На некоторых данных он чуть проиграет, на некоторых данных сильно выиграет, т.е. всреднем оптимальнее.
Но при 200Гб ,уверен, Запрос +Тз в данной задаче захлебнется .
# Ответить
20. Шёпот теней 25.11.2009 20:28
пакеты запросов ...
вложенный запрос ...
запрос+ТЗ ...

... чтобы понять быстродействие - нужно понять "физику" этих процессов ...

тогда и писать меньше надо будет ...

ВОТ мне и хочется чтобы ТЫ прояснил данную "физику" - дЫк чем оТличается вложенный_запрос от пакетного_запроса ...

... тогда можно будет и поговорить более предметно и детально ... без МЕТАфизики ...

... вотТАКОЕпредложение ...

... вот ... а вот если тЫ этого не знаешь ... ? ... ! тогда твоя статья ЭТО профанация .. гадание на кофеёной гуще ... "залезе не залезе.... или пролезе ... неее ... нЕпролезе ..."

... вОООООттакаявОООООтпрОООООвОООООкация ...

...
Ответили: (38) (30) (27)
+ 1 [ hogik; ]
# Ответить
21. I_G_O_R (файл скачал) 25.11.2009 20:41
а где замеры производительности и планы выполнения??? просто так не верю :D
Ответили: (120) (23) (127)
# Ответить
22. I_G_O_R (файл скачал) 25.11.2009 20:46
в запросе №5 соединение по Периоду - это ошибка я уже писал :D, нужно соединять по МоментВремени
Ответили: (23)
# Ответить
23. Ish_2 25.11.2009 21:48
(21) Никаких замеров.
Это демонстрационный вариант. Оптимального алгоритма. Для возможного изучения . И не более того.
(22) В тексте темы указано на это упрощение (уникальный период).
По моменту времени нельзя сортировать и соединять временные таблицы.
Это недостаток 1с платформы. Момент времени может использоваться только в при выборке из регистров для соединения или сортировки .
# Ответить
24. I_G_O_R (файл скачал) 25.11.2009 22:06
По моменту времени нельзя сортировать и соединять временные таблицы.
Это недостаток 1с платформы.

откуда такие данные?
вот только сделал в кострукторе:
ВЫБРАТЬ
	ВзаиморасчетыСРаботникамиОрганизаций.Физлицо,
	ВзаиморасчетыСРаботникамиОрганизаций.Регистратор,
	ВзаиморасчетыСРаботникамиОрганизаций.СуммаВзаиморасчетов КАК Сумма,
	ВзаиморасчетыСРаботникамиОрганизаций.МоментВремени
ПОМЕСТИТЬ ВТДолги
ИЗ
	РегистрНакопления.ВзаиморасчетыСРаботникамиОрганизаций КАК ВзаиморасчетыСРаботникамиОрганизаций
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ВТДолги.Физлицо КАК Физлицо,
	ВТДолги.Регистратор,
	ВТДолги.МоментВремени КАК МоментВремени,
	ВТДолги.Сумма,
	СУММА(ВТДолги1.Сумма) КАК СуммаИтогом
ИЗ
	ВТДолги КАК ВТДолги
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТДолги КАК ВТДолги1
		ПО ВТДолги.Физлицо = ВТДолги1.Физлицо
			И ВТДолги.МоментВремени >= ВТДолги1.МоментВремени

СГРУППИРОВАТЬ ПО
	ВТДолги.Физлицо,
	ВТДолги.Регистратор,
	ВТДолги.МоментВремени,
	ВТДолги.Сумма

УПОРЯДОЧИТЬ ПО
	Физлицо,
	МоментВремени
...Показать Скрыть




Сделано допущение, что поле "Период" в справочнике "Обороты" содержит только уникальные значения.
- это серьезное допущение, и в базе 200 гигов такое гарантировать никак нельзя
Ответили: (26) (25)
# Ответить
25. Ish_2 25.11.2009 22:12
(24) Хм..Странно. А у меня не получилось, правда, давно.
Если это так , как ты пишешь и ты проверил исполнение ,то виноват !

И не получилось еще вот что , после выгрузки в таблицу значений - сортировать по Моменту времени нельзя (неправильно получается)- это уже совсем недавно.
# Ответить
26. Ish_2 25.11.2009 22:17
(24) серьезное допущение сделано намеренно с целью упрощения понимания основного принципа алгоритма. Т.е. для демонстрации.
Для реальной конфигурации конечно запрос должен быть переделан.
Справочник "Обороты" - экзотика, тоже ведь серьезное допущение ,а ты его не упомянул .
# Ответить
27. anig99 25.11.2009 22:49
(20) Радченко для тебя авторитетен?
ИТС, где читал про оптимизацию запросов, с собой нет, поэтому погуглил

Вот отсюда http://devtrainingforum.v8.1c.ru/forum/thread.jsp?id=539555
Сообщение номер 539689

Re: Оптимизация запросов 22.12.2008 16:15
Максим Радченко, 1С
539689

Сами по себе вложенные запросы не страшны. Страшны соединения с вложенными подзапросами. Их использование очень затрудняет выбор оптимального плана для СУБД. Поэтому высока вероятность ошибки оптимизатора и, соответственно, катастрофического замедления запроса.


Разница в производительности может быть огромной. Например, при выборе правильного плана запрос может работать 1.5 сек, а при выборе неправильного - 18 часов (это реальный случай).


Поэтому следует всегда избегать соединений с вложенными подзапросами. Вместо этого надо использовать временную таблицу.
При использовании временной таблицы запрос будет всегда работать стабильно быстро. Ключевое слово тут - стабильно. Запрос, содержащий соединения с вложенными подзапросами, тоже может иногда работать быстро. Но гарантировать этого нельзя.

......

Обратите внимание, что существует экзотический случай, когда вложенный подзапрос ни с кем не соединяется. То есть написано
ВЫБРАТЬ ИЗ (ВЫБРАТЬ ИЗ ( ВЫБРАТЬ ИЗ ...)))

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


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


Ну о том, что один правильный запрос в SQL версии много быстрее цикла с множеством запросов или проход по таблице значений с условиями, спорить не будем?
Ответили: (30) (28) (127)
# Ответить
28. Ish_2 25.11.2009 22:57
(27) Почему ты в своем запросе во временных таблицах не использовал МоментВремени ?
Ведь гораздо удобнее писать Таблица1.МоментВремени = Таблица2.МоментВремени ,чем как у тебя ?
Ответили: (29)
# Ответить
29. Александр Медведев 25.11.2009 23:21
(28) В виртуальных таблицах вроде нет момента времени....
Ответили: (32)
# Ответить
30. Шёпот теней 25.11.2009 23:57
(27) ... ммм ... не хочется вступать в открытую полемику не в "своей теме" ... (20) адресован к Исх_2 и более глубок чем твой ответ ... НО ? ...

1. что значит правильный ?
2. что значит быстрее ?

...

вопрос заключается : если знаешь принцип построения запросов - язык прежде всего декларативный а внутри правила выборки и соединения (оптимизация на основании внутренних алгоритмов) - то тогда можно и сделать правила и ответить на вопрос: когда и где и как и в каком запросе как соединять и как выбирать ...

... а то что вложеные запросы надо переводить во временные таблицы - и так все знают - везде об этом пишут НО на уровне общих рекомендаций ...

могу порекомендовать следующую ссылку и далее ссылки по всему тексту: http://www.gilev.ru/1c/81/index/optimquery.htm ...

... а то, что написано ТУТ - напоминает тексты об УправленческомУчёте - и красиво и похоже на правду и хочется верить - но начинаешь повторять и не получается ...

... вот ...
Ответили: (39) (34) (33) (31)
# Ответить
31. Ish_2 26.11.2009 00:25
(30) Шепот ,я сразу не ответил . Шуровал на теме Суппорта по скачиваниям. Бестолку ,конечно. Но и молчать нельзя.
Сейчас отвечу подробно.
# Ответить
32. I_G_O_R (файл скачал) 26.11.2009 00:26
(29) я что-то не пойму, почему у тебя один раз логин пишится, другой - полное имя?
# Ответить
33. Ish_2 26.11.2009 00:57
вопрос заключается : если знаешь принцип построения запросов - язык прежде всего декларативный а внутри правила выборки и соединения (оптимизация на основании внутренних алгоритмов) - то тогда можно и сделать правила и ответить на вопрос: когда и где и как и в каком запросе как соединять и как выбирать ...


(30)Всё не так. Язык запросов SQL (стандарт пока только один -92г.)- описание синтаксиса, он сам по себе - и внутри у него ничего не сидит.
Разные производители придумывают разные оптимизаторы , например оптимизатор SQL-сервер. Описание внутренней структуры оптимизатора никто не публикует и не документирует(документация отсутствует и у оптимизатора запросов 1с в файловом варианте). И для нас он - черный ящик. Мы , строго говоря , лишь догадываемся , что там внутри и не можем
"ответить на вопрос: когда и где и как и в каком запросе как соединять и как выбирать ... "

Представляешь в какое положение попадает разработчик ?
Написав сложный запрос с вложенными запросами - он НЕ ЗНАЕТ как запрос будет выполняться в каждом конретном случае у каждого конкретного оптимизатора разных фирм !!!

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

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

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

Третье соображение : продемонстрировать для публики (см. тему) запрос с временными таблицами и показом промежуточных результатов удобнее . Легче разбираться в нем и другому программисту.

Декларативность языка запросов ИЗНАЧАЛЬНО предполагает неопределеность в вопросе КАК ? В КАКОМ ПОРЯДКЕ ? и не дает на этот вопрос никакого ответа.

Т.е. я напишу сейчас запрос тебе простенький( с вложенным) и ни ты и никто не скажет определенно как он будет выполняться.
УФФ !
Ответили: (35)
# Ответить
34. Ish_2 26.11.2009 01:07
(30) Забыл сказать еще об одном коварстве оптимизатора.
Один и тот же запрос может выполняться по - разной схеме(последовательности действий) в зависимости от размера используемых таблиц . Ты представляешь какая это засада ?
И рассказ о том , что все было хорошо и работатло , а потом вдруг БАЦ и какой то мелкий запросик вместо выполнения в доли секунды - выполняется !! сутки!!! - это не байки . Это проделки оптимизатора запроса.
Ответили: (35)
# Ответить
35. Шёпот теней 26.11.2009 05:30
(33), (34) ... болтун ... не верю ...

ваши и статья и комментарии разговор о повседневном, без желания обсуждать, без утверждений, без "глубины" и без "ширины" рассматриваемого вопроса ... лужа ...

... как всегда уход от желания обсуждать в сторону использования нескольких демагогических прАвил - для бега по кругу ... нет желания Зделать проблему "прозрачной", наоборот, утопить её в не связанных цифрах, чтобы оставить лазейки для бегства - типа это упрощение - вот ваша цель ...

... у вас есть хороший оппонент - ... I_G_O_R ... - вот его публикациям и комментариям я верю ... есть чему по-учиться ... и есть желание залезть в интернет ...

... вотТАКАЯкритика ...
Ответили: (37) (36)
− 2 [ awa; artbear; ]
# Ответить
36. Ish_2 26.11.2009 06:47
(35) Ну ,привет. Шепот, я же старался .
Смотри сколько писанины развёл . Ох, злой человек ты человек !
# Ответить
37. Ish_2 26.11.2009 07:04
(35) Черт с тобой, уломал.
Сформулируй четко вопрос и я тебе на примере какого либо запроса - отвечу (Обнажу "физику процесса") .
Ответили: (38)
# Ответить
38. Шёпот теней 26.11.2009 08:00
(37) ... опять болтунишь ... а как же (20) ... ?
# Ответить
39. Ish_2 26.11.2009 08:27
(39)
ВОТ мне и хочется чтобы ТЫ прояснил данную "физику" - дЫк чем оТличается вложенный_запрос от пакетного_запроса ...


Отвечаю прямо об отличии :
Вложенный запрос - это часть другого запроса.
Пакетный запрос   - это совокупность последовательно выполнямых  
                            запросов.


Если ты имеешь ввиду отличия между выполнением одной и той же задачи разными способами
1. Запросом, имеющим вложенные запросы
2. Пакетным запросом ( последовательное выполнение нескольких простых запросов).
И задаешь вопрос , так сказать, какова "физика" этих отличий ?
То я спрашиваю , нафига я писал (30) ?

Если ты понимаешь под "физикой" отличий что-то другое - дай определение
этой "физики".
Ответили: (41) (40) (39)
# Ответить
40. Ish_2 26.11.2009 08:52
(39) Что касается твоей ссылки
http://www.gilev.ru/1c/81/index/optimquery.htm
то несомненно нужная и полезная статья ,
приоткрывающая дверь к кухне интерпертации запросов 1с в SQL.
Но эта информация полезна для очень ограниченного круга специалистов, разрабатывающих какие -то специализированные решения на платформе 1с . Статья эта лишь на другом уровне и подробностями раскрывает ,то что есть уже у Радченко.
Поэтому следует всегда избегать соединений с вложенными подзапросами. Вместо этого надо использовать временную таблицу.
При использовании временной таблицы запрос будет всегда работать стабильно быстро. Ключевое слово тут - стабильно. Запрос, содержащий соединения с вложенными подзапросами, тоже может иногда работать быстро. Но гарантировать этого нельзя.


Для огромного подавляющего большинства 1с-ников этого вполне достаточно.
Мало того , почти наверняка, можно сказать :
1с-ник ! Если у тебя проблемы и ты полез смотреть как 1с запрос интерпретируется в SQL-запрос - ЗНАЙ : ты не знаешь как правильно составлять запросы.
+ 1 [ Redokov; ]
# Ответить
41. Шёпот теней 26.11.2009 09:07
(39) ... хм ...

вопрос1:
... дык при каких условиях и пАчему Пакетный запрос выполняется быстрее ...?

вопрос2:
... дык как же Зделать Нарастающий Итог в запросе ...?

самый простой тип нарастающего итога это нумерация строк запроса ... прошу тебя не влезая в дебри конфигурации:
1. покажи нАм
и
2. рАсскажи нАм
и
3. укАжи нам
... способы создания нарастающих итогов в запросах ...

... лично мне интересно .... сделай это дополнением к статье ... я до сих пор не умею делать нарастающие итоги ... хотя бы нумерацию освоить ... а вот понятных изложений пока не нашЁл ... только по простому - чтобы даже мне было понятно ...

думаю это будет интерсно и важно и познавательно для многих ...

... вОООт ...
Ответили: (43) (42)
# Ответить
42. Ish_2 26.11.2009 09:25
(41) Пакетный запрос НЕ ВЫПОЛНЯЕТСЯ БЫСТРЕЕ ,чем аналогичный правильно понятый оптимизатором запрос с вложенным запросом.
Ключевые слова здесь "правильно понятый". Чтобы избежать вероятности "неправильной понятости" и применяют пакетный запрос.

Сегодня подготовлю демо-вариант с нарастающими итогами с наглядным примером.
# Ответить
43. Александр Медведев 26.11.2009 09:27
(41) вообще-то это есть в моей статье - в самом начале....
Пакет запросов скорее всего будет выполнятся быстрее, чем объединение вложенных запросов. Причиной тому - сложность для оптимизатора SQL работы с объединением вложенных запросов. Гораздо меньше неоптимальных инструкций SQL возникает при разборе простых запросов и дальнейшей передаче по цепочке временных таблиц.

З.Ы. Честное слово... Такое ощущение, что специально упускаешь из внимания некоторые моменты, которые были уже сказаны
Ответили: (48) (45) (44)
# Ответить
44. Ish_2 26.11.2009 09:43
(43) А я сделаю всего лишь еще один нагядный пример к твоей статье.
То же самое , но другими словами.
# Ответить
45. Шёпот теней 26.11.2009 10:23
(43) ... помню твою статью ...

но твоЁ изложение слишком "продвинуто" и а изложение Исх_2 - запутано ...

может ВЫ и понимаете - а я нет ...

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

... хочется как-то более простых и наглядных примеров: типа: как составить запрос: 1. выбрать номенклатуру из папки разрезе характеристик,
+
2. найти остатки в разрезе выбранныйСклад-номенклатура-характеристика,
+
3. найти зарезервировано в разрезе выбранныйСклад-номенклатура-характеристика,
+
4. вывести свободный остаток в разрезе выбранныйСклад-номенклатура-характеристика

и даже бог с ним с разбиением по периодам ...

... если бы меня кто этому научил - последовательно и обЪясняя по шагово - спАсибо бы сказал ...

... вот ...
Ответили: (46)
# Ответить
46. Ish_2 26.11.2009 11:23
(45) Сделал приложение : Что такое нарастающие итоги ? И зачем они нуны ?.
Посмотри.
Ответили: (47)
# Ответить
47. Шёпот теней 26.11.2009 11:59
(46) ... спасибо ... сегодня обязательно посмотрю, доложусь как понял ... вот ...
# Ответить
48. Ish_2 26.11.2009 12:04
(43) Посмотри приложение к статье. Как ?
Ответили: (49)
# Ответить
49. anig99 26.11.2009 12:20
(48) вроде нормально
# Ответить
50. Drock 27.11.2009 20:58
однозначный плюс
Ответили: (52)
# Ответить
51. gilv 27.11.2009 21:48
вот вам занятся не чем,
работа по вам плачет :D
Ответили: (53) (52)
# Ответить
52. Ish_2 27.11.2009 22:14
(50) Спасибо.
(51) Ага. Со скуки.
# Ответить
53. Шёпот теней 27.11.2009 23:09
(51) ... без теории НЕТ практики ... теория ЕСТЬ основа науки ...

... кстати вам не обидно, что из 24 часов только 8 тратите на работу ...

... вот ...
Ответили: (57) (55) (54)
# Ответить
54. Александр Медведев 28.11.2009 11:08
(53) мне обидно в сутках всего 24 часа и спать надо...
# Ответить
55. Ish_2 28.11.2009 14:09
(53) Любимое занятие в субботу : придираться к Шепоту.
Так вот
... без теории НЕТ практики ... теория ЕСТЬ основа науки ...


Пальцем в небо. Тяжело дается диалектический подход . Получше будет так:
Научный подход подразумевает :
Без теории нет практики. Без практики нет теории.
Ответили: (56)
# Ответить
56. Шёпот теней 28.11.2009 14:51
(55) ... вах ... Ish_2 ... ах ... Ish_2 ... ох ...

... твоЁ желание придраться больше чем "Правда" и выше чем "Истина" ...

... основой науки есть повторяемый опыт как Эксперимент и Опыт как опыт ...

... поэтому его сначало "наблюдают" потом "описывают", потом "повторяют" ...

... именно поэтому без Теории нет Науки ... нет Практики ... нет Опыта ...

... хотя некоторых Теория никогда не станет Опытом пока они не получат опыт ...

... вотТАКАЯтеория ...
Ответили: (61)
# Ответить
57. gilv 28.11.2009 14:53
(53) Теории меня не убеждают.
Я предпочитаю находить ответы экспериментальным путем.
Но своих убеждений стараюсь не то что не навязывать, а отговаривать от них. Вообщем, главное, без фанатизма. 8-)
Ответили: (59) (58)
# Ответить
58. Шёпот теней 28.11.2009 15:43
(57) ... смЕЕЕшно-с ...

без ТЕОРИИ нет эксперимента ... !!! ... однозначно !!! ...

... есть холерики - им проще 40 раз сбегать и один раз подумать ...
... есть меланхолики - им проще 40 раз подумать и один раз сбегать ...

НО ! но сначало ТЕОРИЯ а потом Эксперимент ...

... вот ...
# Ответить
59. Ish_2 28.11.2009 15:50
(57) Если автор публикует свое мнение , он уже его в каком -то смысле "навязывает". если автор при этом отговоривает читателей или занимет позицию , дескать я тут мимо проходил, - хитрость эта никакого отклика как правило не находит, а находит недоумение.
Назвался автором - будь им : "навязывай" свой взгляд ,ты этим взглядом и отличаешься от других
Ответили: (62) (60)
# Ответить
60. Шёпот теней 28.11.2009 15:54
(59) ... ого ... НУ НИ ЧЕГО СЕБЕ ... заявлениЦЕ ... ухххтыыы ...
# Ответить
61. Ish_2 28.11.2009 15:56
(56) Срезал.
# Ответить
62. Шёпот теней 28.11.2009 16:04
(59) ... ? убил ! ...
# Ответить
63. Eugeneer 28.11.2009 18:02
Ой написали то... с ума сойти. точно все не перечитать. и статья слишком большая для данной задачи. Пока автор писал статью можно было 10 раз модифицировать регистр взаиморасчеты под списание по фифо (с заполненными сделками) и вообще никаких бы пакетных запросов не понадобилось.
Четно - не хочу парить даже мосх чтением. задача решена всеми - всех поздравляю. Ждем 11 торговлю , 8.2, агрегаты и прочее...
Смысл мосх ломать.
По поставленной задаче я уже давно прелдожил написать её одним запросом с коррелированными подзапросами (думаю это решение) но руки не доходят.
Ответили: (64)
# Ответить
64. Ish_2 28.11.2009 18:28
(63) Дождались Евгения.
Над чем тут мозг ломать - есть.

Речь ведь идет не только о решении конкретной задачи , но и об ощем подходе к использованию нарастающих итогов в запросе.
Если бы ты хоть чуть-чуть расшифровал слова здесь или в статье
"запрос с коррелированными подзапросами" - появилось бы еще одно решение - возможно самое оптимальное.
А 8.2 и агрегатами пугать простую публику не стоит.
Ответили: (66)
# Ответить
65. Eugeneer 28.11.2009 18:31
а пока рейтинг приложенных разработок говорит сам за себя :))
и опять не раскрыта тема почему мелкие подзапросы хуже. "лучше передать серверу" ну а мелкие что не сервер обрабатывает чтоли?
и я лично пока под большим сомнением что проще, мегазапрос или гораздо меньше по объему кодинговый алгоритм.
В мегазапросе можно часами просидеть если понадобится решить малейшее отхождение по задаче.

"В настоящий момент , автор статьи считает , что прав в споре - Anig99. Опуская аргументацию почему Eugeneer и Ish_2 неправы (пожалуй , потянет на отдельную статью о вредности "семерочного" похода при работе с таблицами БД)" спасибо. посмеялся. автор где то нашел семерочные подходы )))
Ответили: (72) (71)
# Ответить
67. Eugeneer 28.11.2009 18:39
ВОт пример коррелированного подзапроса. Построение запроса внутри собственного запроса:
ВЫБРАТЬ
ПродажиОбороты.Номенклатура КАК Номенклатура,
ПродажиОбороты.Номенклатура.Родитель КАК Группа,
ПродажиОбороты.СтоимостьОборот КАК СтоимостьОборот
ПОМЕСТИТЬ Продажи
ИЗ
РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты
;

////////////////////////////////////////////////////////////­////////////////////

ВЫБРАТЬ
Продажи.Номенклатура,
Продажи.СтоимостьОборот КАК СтоимостьОборот,
Продажи.Группа КАК Группа
ИЗ
Продажи КАК Продажи
ГДЕ
Продажи.Номенклатура В
(ВЫБРАТЬ ПЕРВЫЕ 5
ВложенныеПродажи.Номенклатура
ИЗ
Продажи КАК ВложенныеПродажи
ГДЕ
ВложенныеПродажи.Группа = Продажи.Группа
УПОРЯДОЧИТЬ ПО
ВложенныеПродажи.СтоимостьОборот УБЫВ)

УПОРЯДОЧИТЬ ПО
Группа,
СтоимостьОборот УБЫВ
ИТОГИ ПО
Группа
Ответили: (86)
# Ответить
68. Eugeneer 28.11.2009 18:42
Вот еще вариант из ссылки (кстати по этому варианту очень просто по взаиморасчетам решить задачу, испольузется условие по методу ИМЕЮЩИЕ, если сделать по нужной сумме то будет решение):
ВЫБРАТЬ
ПродажиОбороты.Номенклатура.Родитель КАК Родитель,
ПродажиОбороты.Номенклатура КАК Номенклатура,
ПродажиОбороты.КоличествоОборот КАК Количество
ПОМЕСТИТЬ Продажи
ИЗ
РегистрНакопления.Продажи.Обороты(, , , ) КАК ПродажиОбороты
;

////////////////////////////////////////////////////////////­////////////////////

ВЫБРАТЬ
Продажи.Родитель КАК Родитель,
Продажи.Номенклатура КАК Номенклатура,
Продажи.Количество КАК Количество
ИЗ
Продажи КАК Продажи
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Продажи КАК ПродажиНумерация
ПО Продажи.Родитель = ПродажиНумерация.Родитель
И Продажи.Количество <= ПродажиНумерация.Количество

СГРУППИРОВАТЬ ПО
Продажи.Родитель,
Продажи.Номенклатура,
Продажи.Количество

ИМЕЮЩИЕ
КОЛИЧЕСТВО(ПродажиНумерация.Количество) <= 5

УПОРЯДОЧИТЬ ПО
Родитель,
Количество УБЫВ
Ответили: (86)
# Ответить
69. Eugeneer 28.11.2009 18:43
В итоге получится запрос который будет помещатся на экранный лист. Но уж простите читать запросы в тысячи строк просто лом и нет времени.
# Ответить
70. Eugeneer 28.11.2009 18:44
Я у Аника посмотрел запрос мне чуть плохо не стало. десяток временных таблиц и кода много.
Ответили: (79) (78)
# Ответить
71. Ish_2 28.11.2009 19:05
(65) Ссылка твоя не открывается.

1. Рейтинг - это не аргумент. Рейтинг - это повод поинтересоваться - а что там ?
2. Запрос в цикле - это зло. Широко известное еще до изобретения "семерки".
Применяется исключительно редко (например тогда , когда результат общего запроса может быть оч.оч. большим по размеру.)
Серверу не все равно обрабатывать кучу мелких запросов или один большой.
Разумеется , быстрее будет выполнен один общий правильно составленный запрос. Хотя бы потому что, обращение к базе данных будет всего одно (а это время !). Поэтому всегда нужно стремиться к одному запросу, а не к циклу запросов.
Убедиться в этом можно практическим путем. Перепиши свой отчет - сделай один запрос к базе для всех контргаентов . Получи выходную таблицу за один проход выборки. Сравни время.

Один запрос , набранный в конструкторе , технологичней в использовании.
Применяя "Запрос + кодинг" для больших баз ты жестко привязан к "силе клиента" , к сети и т.д, т.к. часть кодинга выполняется на "клиенте". Передавая обработку на сервер ты отвязываешься от этих проблем.
Для базы 120 Гб применение твоего запороса в цикле неприемлемо в принципе.

Так вот кратенько...
Ответили: (73)
# Ответить
72. Ish_2 28.11.2009 19:06
(65) Сейчас. Прочитаю твои запросы.
# Ответить
73. Eugeneer 28.11.2009 19:10
(71) не вижу аргементов. "это зло" - это не аргумент. базы данных созданы для того чтобы к ним сотни тысячи и миллионы запросов каждую секунду поступали. 1С многопользовательская среда. каждую долю секунды к базе строятся тысячи запросов при любой работе (открытии справочника, документа, кто то отчет крутит, кто то еще что то делает).
Запрос в цикле а что в этом плохого? вот поясните аргументированно.
в типовых 1С можно найтьи десятки примеров где в циклах выполняются и запросы и что?
# Ответить
74. Eugeneer 28.11.2009 19:11
Да причем тут 120г. может у него 100г там порнухи в хранилище. размер не показатель. тем более речь об одном единственном регистре. сколько он из этих 120 г занимает и причем тут вообще размер базы. да хоть 500г хоть 2000г. какая разница.
Ответили: (78)
# Ответить
75. Eugeneer 28.11.2009 19:13
не смешите такпочки. часть кодинга выполняется на клиенте. ты бы сначала глянул конкретно что там выполняется. небольшая таблица окончательная из нескольких тысяч строк - тьфу. тут даже смотреть нечего.
Ответили: (76)
# Ответить
76. Ish_2 28.11.2009 19:43
(75) Женя ,виноват.
Сейчас не могу. Позднее. Завтра- послезавтра обязательно отвечу.
# Ответить
77. Шёпот теней 28.11.2009 20:35
нет Ish_2 ... не ответишь ... не позднее ... и никогда ... не сможешь ...

... порвЁт тебя Eugeneer как тузик грелку ...

... и хорошо ... может чего-нибудь и надумаешь ...



... вот ... без злорадства но с надеждой ...
− 1 [ artbear; ]
# Ответить
78. Александр Медведев 28.11.2009 20:35
(70) Можно не коверкать? Вы банально не уважаете своих собеседников. Здесь не миста.
(74) 120 гигов, пустое хранилище, база за 4 года, по 10 тыс документов реализации в месяц. Так понятнее? Куча виртуальных таблиц - это реализация алгоритма. Если его понять, остальное - тут же становится ясно. Я и не надеялся, что кто-то без разъяснений алгоритма разберется (хотя нашелся как минимум 1 человек, который разобрался без моих дополнительных объяснений).

З.Ы. Сейчас я не буду впадать в полемику. Хочу отдохнуть на выходных
+ 1 [ artbear; ]
# Ответить
79. I_G_O_R (файл скачал) 28.11.2009 23:25
(70) ЗУП открой ты вообще ох..ешь, модуль ПроведениеРасчетов, функция ПолучитьДанныеДляРасчета. На экзамене спеца по ЗУП за 4 часа туда еще и изменения внести надо, а 10 ВТ - это мелочи, так что это не критерий.
Ответили: (81) (80)
# Ответить
80. Александр Медведев 29.11.2009 00:24
(79) Согласен... Не всегда всё сложное нужно резать бритвой Оккама... Как я уже писал в какой-то из веток по данной тематике - нужно соизмерять ценность результата и сложность его получения.
Ответили: (81)
# Ответить
81. Шёпот теней 29.11.2009 09:43
(79), (80) ... удивили ...

... выбран слишком простой демагогический приЁм, чтобы увести разговор от конкретного примера в сторону красоты "филосовской" сложности ...

... уверен, я не провоцирую, Eugeneer вас "отметелит" сложной философской простотой - "бритвы Оккаямы" ...

... вОООт ...

п.с. «Бритва (лезвие) О́ккама» — методологический принцип, получивший название по имени английского монаха-францисканца, философа-номиналиста Уильяма Оккама (Ockham, Ockam, Occam; ок. 1285—1349). В упрощенном виде он гласит: «Не следует множить сущее без необходимости»

...
# Ответить
82. Александр Медведев 29.11.2009 10:10
(82) Никуда я не увожу, я просто сокращаю свой пост за счет емкого понятия на уровне 1го курса института. Все рассуждения Eugeneer можно свести именно к Бритве Оккама - не плодить сущностей без надобности или усложнять сверх необходимости. Ключевые слова здесь "надобности" и "необходимости". Кроме того, он абсолютизирует свой опыт и считает, что проблемы больших объемов данных надуманны. Мой пост относился именно к нему, а не к тебе, Шепот.
С тобой всё по другому. Я никак не могу понять, что тебе надо. То ты просишь раскрыть механику оптимизатора запросов SQL - а это теория, т.к. для каждой базы всё будет по-разному. То ты заявляешь, что тебе нужна конкретика - покажите запрос. То ты пишешь пост в стиле "дао программирования". И всех обвиняешь в увиливании...Никто с темы слезть не пытается. Просто люди по-разному воспринимают проблему: кто-то конкретно запрос на дебиторку, кто-то запрос с нарастающими итогами, кто-то преимущества разных вариантов сочетания запросов и кода, а кто-то вообще не видит проблемы. Одно твое желание я знаю точно - расшевелить болото.
Ответили: (83) (82)
+ 1 [ larisab; ]
# Ответить
83. Шёпот теней 29.11.2009 10:57
(82) ... то ли побил ... то ли похвалил ... то ли ...

... но ткнул понятием 1 курса ... ещЁ один демАгоический приЁм ...
... прям как у М.Жванецкого "... что может сказать хромой об исскустве Герберта Фон Караяна, если ему сразу сказать что ОН хромой ..." ...

... значИтельность не может быть больше знАчимости ...

... вот ...
# Ответить
84. I_G_O_R (файл скачал) 29.11.2009 12:14
ШёПоТ провоцирует,не слушайте(точнее не читайте) его, он любитель поспорить.
# Ответить
85. Шёпот теней 29.11.2009 13:33
I_G_O_R ... хм ...

1. уважаю ваше мнение ...
2. мне хочется знать то чего не знаю, в чём сомневаюсь, то что хочу знать ещё лучше ...
3. методы получения знаний могут быть разные ...

но когда на конкретный вопрос о 2*3 тебе начинают говорить об "ИНТЕГРАЛЬНЫХ МЕТОДОВ ДЕТЕРМИНИРОВАННОГО ФАКТОРНОГО АНАЛИЗА" поневоле начинаешь задумываться ... так ли нужна сложность интеграла в получении утроенного сложения ... такая вот дЕмагогия ...

... вот ...
# Ответить
86. Ish_2 30.11.2009 11:54
(67),(68) Два примера запросов отвечают на вопрос о самых продаваемых товарах.
И в полях выборки используется номенклатура.
Какое отношение они имеют к задаче получения просроченных долгов контрагентов ? Чем они нам помогут ?
В таком случае , возможно , лучше опубликовать статью где раскрыть замысел полностью.

А вот , неравенство в условии соединения запроса (68) имеет прямое к текущей теме .
Рассмотрим чаить этого запроса
ВЫБРАТЬ
    Продажи.Родитель КАК Родитель,
    Продажи.Номенклатура КАК Номенклатура,
    Продажи.Количество КАК Количество
ИЗ
    Продажи КАК Продажи
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Продажи КАК ПродажиНумерация
        ПО Продажи.Родитель = ПродажиНумерация.Родитель
            И Продажи.Количество <= ПродажиНумерация.Количество
...Показать Скрыть


Представим , что в таблице всего одна группа содержащая 10 000 товаров.
(для крупных торговых сетей ничего фантастического, кстати).
Тогда в результате соединения получим таблицу с количеством записей
(10 000+1)/2*10 000 = 50 005 000 (сумма членов арифметической прогрессии). Т.е. размер первоначальной таблицы увеличился более в чем 5 000 раз. Последующая группировка с условием не отменяет необходимости такого соединения , а лишь при получении выходной выборки фильтрует промежуточную таблицу.
Ты не видишь здесь никакой проблемы ?

Так вот текущая статья и статья Anig99 посвящены как раз тому , чтобы избежать таких больших промежуточных таблиц в процессе исполнения запроса.
Приведенный пример не выдумка . С подобной ситуацией столкнулся Anig99 при работе с базой 120Гб.
Поэтому приводя тексты таких запросов лучше предупреждать пользователя :
"Этот запрос пригоден для небольшого количества данных (малые базы до 30Гб). Не вздумайте применять такие подходы для больших баз (более 120 Гб)."
Ответили: (89)
# Ответить
87. Merlin12042009 (файл скачал) 30.11.2009 16:49
анализ...это всегда круто!
Ответили: (127)
# Ответить
88. KukA.5 01.12.2009 21:53
Хорошая статья.
Ответили: (127)
# Ответить
89. Шёпот теней 01.12.2009 21:59
(86) ... ГИГАнтоМАНИЯ ...

... гипноз нулей ...
... кто больше ... 100 ГБ ... 120 ГБ ... 150 ГБ ... 200 ГБ ... 80 000 строк ...
... сумма членов арифметической прогрессии ...

... прямь как в рекламе : не поворяйте этого - это сделано в фотошопе ...

... ВОТ ...
Ответили: (90)
# Ответить
90. Александр Медведев 01.12.2009 23:50
(89) Шепот... родной город обязывает... ничего ровного. Если завод, то большего города, если гостиница, то самая бесполезная и высокая в городе, если легковушка, то меньше всех...
Магия, не магия, но из малого произрастает большое.... Современные компьтеры расхолаживают программистов позволяя не задумаваться об оптимизации кода и экономии памяти. В результате получаем расчет себестоимости и корректировку стоимости списания по 6 часов... Перешли для получения нового функционала и получения аналитики - но плата за это - длительность не очень сложных расчетов. Вот проблема на самом деле.
Ответили: (93) (91)
# Ответить
91. Шёпот теней 01.12.2009 23:55
(90) ... убил ... (: ...
# Ответить
92. I_G_O_R (файл скачал) 02.12.2009 00:06
скорую вызывайте :o
# Ответить
93. Ish_2 02.12.2009 10:14
(90) Вспомнился 1986г . Оперативная память для бортовой БЦВМ измерялась Кб и суровой ниткой делилась между разработчиками различных систем.
Требовалась жесточайшая экономность кода.
Эти Кб занимали , обменивали , одалживали до след. проекта и т.д.
Началась антиалкогольная компания и Кб обменивали на бутылки.
# Ответить
94. Ish_2 02.12.2009 12:39
(8) Почему-то пропустил твой комментарий - прочитал только сейчас.
В демонстрационном варианте , думаю, возможно и опустить. Но если дашь ссылку где сказано , что всегда лучше индексировать явно таблицу перед соединением в след.статьях буду ставить.
# Ответить
95. Шёпот теней 02.12.2009 12:47
... почти в тему по поводу идексирования : http://interpretor.ru/sql_indexing ...

... почти в тему но не совсем : http://www.interface.ru/home.asp?artId=3514 ...

...вот ...

...
Ответили: (96)
+ 1 [ artbear; ]
# Ответить
96. Ish_2 02.12.2009 13:06
(95) Несколько не то. То что выборка у таблицы с индексом будет осуществляться быстрее - само собой.
Но если мы только получили временную таблицу - индекс у нее отсутствует.
Оптимизатор запроса или мы явно должны ее индексировать ?
Я не нахожу большой разницы . Артур считает , что надежнее всё-таки явно её проиндексировать.
# Ответить
97. Ish_2 02.12.2009 13:12
(8) Впрочем, ненужно ссылки. И так понятно , что ты прав.
Ответили: (98)
+ 1 [ artbear; ]
# Ответить
98. artbear 02.12.2009 17:00
99. alexqc 10.12.2009 13:02
А тем не менее, "пройтись циклом" действительно самый оптимальный вариант. Его трудоемкость O(n), в то время как трудоемкость варианта объединения двух таблиц - от O(n * log n) если хорошо сработает оптимизатор до O(n^2) в плохих случаях. Так что, не стоит тыкать пальцем и покатываться со смеху с предлагающих это "семерочников". И говорить про слабость клиента тоже не стоит - раз клиент получил набор данных, значит, что-то уже с ним будет делать (да хоть, например, выводить) и обязательно хоть разок, но пройдет по набору. Вычисление итогов в этом случае - небольшой довесок к выполнению.
Ответили: (101) (100)
# Ответить
100. Ish_2 10.12.2009 13:55
(99) Вначале статьи приведены 3 варианта решения задачи.
Под пунктом 2 приведено первоначальное мнение автора этой статьи.
Полностью совпадающее с Вашим. Вообще говоря, количество операций (трудоемкость) при этом варианте значительно меньше.
И если в кого-то автор тыкает пальцем и покатывается со смеху , то прежде всего в себя.
Первый вариант (запросы в цикле) был рассмотрен выше в коментариях.
Надеюсь Вы согласны, что запрос в цикле - это зло.
Второй вариант (одним запросом получить выборку для всех контрагентов и из нее получить выходную таблицу) имеет одно ограничение.
Мы не знаем периода этого запроса ( какова самая рання дата неоплаченного документа ), т.е. вынуждены выгружать на клиента все обороты всех контргаентов за весь период. До определенного размера базы этот ограничение не имеет смысла. Но ведь где -то этот предел существует ! И время передачи только одной выходной таблицы запроса может стать неприемлемо большим.
Для конфигурации в крупной розничной сети , торгующей по дисконтным картам 3-4 года, это ограничение может быть актуальным. Грузить на клиента огромную выборку проблематично.
Говорить о слабости клиента стоит !
При использовании подхода "все в одном запросе" на клиента поступает очень небольшая таблица для визуального отображения и не более того.
Это и есть важнейшее преимущество третьего подхода - его универсальность. Технологичность же подхода определяет отсутствие кодинга : запрос составляется в конструкторе.
Поэтому такой подход и был назван оптимальным : на малых базах(до 30 Гб)много не проиграет , на больших выиграет.
Ответили: (103)
# Ответить
101. Александр Медведев 10.12.2009 14:05
(99) Самый оптимальный для чего????
Вот пример...
Для бомжа жить под теплоцентралью и бутылки собирать - оптимальный вариант... Тепло, относительно сухо, почти каждый вечер можно собрать на бутылку и закусь... Зашибись. Самый оптимальный вариант - для бомжа...
А вот попробуйте таким образом собрать на Ламборджини??? Мало того, что бутылки собирать будете пол жизни, так вам ещё нужно найти кто бомжику без паспорта Ламборджини продаст... так ещё и ездить как-то надо научится, на бензин опять-таки.
С другой стороны, нафуа бомжу Ламборджини??? Ведь большинство бомжуют не из-за отсутствия способностей, а из-за нежелания работать и/или удовлетворения текущим положением вещей.
А положение вещей, конечно, может быть разным... Может климатические условия очень хорошие - бананы там всякие, кокосы... или бомжик совсем маленький и Ламборджини ему игрушечной хватает....
Тут сразу столько оптимумов появляется... Ух...

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

А мы здесь обсуждаем как БЫСТРО заработать на Ламборджини, а не как легко прожить.
Ответили: (104) (102)
# Ответить
102. Ish_2 10.12.2009 14:17
(101) Ух... ты-ы.
# Ответить
103. alexqc 10.12.2009 19:02
(100) Да, под п.2 мнение совпадающее с моим, однако далее Вы приходите к тому что лучше скрестить 2 таблицы, не говоря почему.

Сейчас вы аргументируя это тем, что "мы не знаем периода запроса".

НО! При подходе "скрестить две таблицы" мы его тоже не знаем!

Дальнейшее рассуждение "При использовании подхода "все в одном запросе" на клиента поступает очень небольшая таблица для визуального отображения и не более того" - значит что? Что по нарастающему итогу делается фильтрация! Т.е. как у вас в статье в приложении. Однако, кроме как там, о фильтре по н.итогу более нигде не сказано - а это всего лишь одно из применений. Может конечно в исходной постановке речь шла именно об том - тут в этих статьях и ссылках друг на друга черт ногу сломит, может я что-то и пропустил - только этого не видно.

Так вот, если задача стоит лишь в определении одного показателя - ее можно решить и другими методами - например, искать остатки двоичным поиском, сужая период.

Ну и наконец, никто не запрещает таки цикл на сервере делать (эта возможность не является стандартом и зависит от реализации, но и MSSQL, и Postgre ее предоставляют). А коли 8ка этого не умеет - проблемы 8ки :). 7.7 с 1С++ это позволяет.
Ответили: (106) (105)
# Ответить
104. alexqc 10.12.2009 19:22
(101) Аналогии хороши для иллюстрации, для доказательства - зло.
Ламборджини - это скорее к САПу.
Встречный вопрос - у Вас очевидно, она уже есть?

А про оптимальность я вполне аргументировал: цикл - линейная трудоемкость, пересечение таблиц - в пределе квадратичная. Говоря Вашими словами - мы покупаем Ломбарджини за ее обычную цену, но предварительно еще оплатив детали, труд сборшиков, механиков и продавца.
# Ответить
105. Александр Медведев 10.12.2009 19:34
(103) См. мою статью там как раз другой метод оптимизации. Чем-то схожий с двоичным.
# Ответить
106. Ish_2 10.12.2009 20:16
(103)
Да, под п.2 мнение совпадающее с моим, однако далее Вы приходите к тому что лучше скрестить 2 таблицы, не говоря почему.
Сейчас вы аргументируя это тем, что "мы не знаем периода запроса".
НО! При подходе "скрестить две таблицы" мы его тоже не знаем!


Предельно конкретно.
У вас 100 контргаентов . Общее количество документов всех контргаентов за весь период 2-4 тыс. Вы выгрузили одним запросом все эти документы в выборку. И за один проход в цикле выборки получили выходную таблицу . Вы выиграете у метода "Все в одном запросе" ? Отвечаю : Да ! Много выиграете ? Отвечаю : несущественно (для пользователя).

И мы с Вами говорим : Ура! "семерочные" подходы рулят !

У Вас 100 000 контрагентов 30 000 000 документов за весь период.
Если Вы скажете что этого мало - я Вам скажу 1 000 000 и 300 000 000.
Не торопитесь выгружать эти обороты в одну таблицу(выборку) и пройтись по ней циклом. Вы жестоко проиграете на одной переброске такой таблицы с сервера на клиента. Вы должны также сказать, что и клиентская машина должна быть очень не простой .
Т.е. появляется масса "НО". Чтобы от этих "НО" отвязаться не проще ли отказаться от перегонки таблиц "сервер-клиент" вовсе , а всю обработку передать на "сервер" , а на клиентскую машину выдавать только результат запроса (оч.маленькую таблицу для отображения в отчете) ?
Это лишь один аргумент.

Второй аргумент . Да , Количество операций в методе "все в одном запросе" больше. Но и выделенный сервер базы данных гораздо мощнее клиентской машины. Операции группирования и суммирования выполняются многократно быстрее чем при при "ручном кодинге цикла" на клиентской машине.

Так вот. Мы не знаем периода запроса для каждого контрагента , но мы его ищем . Сначала суммируем по месяцам - получаем оч.небольшую таблицу - в ней ("срещиваем сама с сбоой") находим нар.итоги . По сумме долга определяем период для каждого контргаента. Согласно этому периоду вырезаем только нужные документы для каждого контргаента , их "скрещиваем" и находим тот самый первый неоплаченный документ.
Это и есть подход , который кажется "ужасно затратным". Но он эффективен т.к. сервер базы данных совершает те операции , для которых он и предназначен.

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

Из Ярославля в Москву быстрее доехать через Владивосток, потому что мы поедем на Сервере Баз Данных .
На дохлом велосипеде (клиентской машине) до Москвы добираться дольше.
Ответили: (108) (107)
# Ответить
107. hogik 11.12.2009 00:01
(106)
"Вы выгрузили одним запросом все эти документы в выборку. И за один проход в цикле выборки получили выходную таблицу ...И мы с Вами говорим : Ура! "семерочные" подходы рулят !"
- Маленькое замечание. В "1С 7.7" цикл выполняется не по выборке, а непосредственно по таблице базы данных. В DBF-ной версии - всегда так. В SQL-ной версии - не всегда. Т.е. термин "семерочные подходы" имеет разный смысл в разных версиях "1С 7.7".
Ответили: (111) (109)
# Ответить
108. Алексей 11.12.2009 11:05
(106) Акцентирую Ваше внимание еще раз: в начальной постановке пропущено (точнее, указано вне основной части и как то вскользь) критическое условие: мы не просто строим н/итоги, мы ФИЛЬТРУЕМ по н/итогу. В таком случае - да, от того где выполняется построение итогов зависит объем пришедшей на клиента выборки, и клиент начинает иметь значение. Но, ИМХО, это все-таки очень частный случай - обычно н/итоги нужны "как есть". Точно также как и просто суммы - случаи, когда производится фильтрация по колонкам sum(), сравнительно немного (и чаще всего это having sum()<>0) - обычно нечто из серии "выбрать крупных клиентов", что уж точно не в оперативной работе применяется.

Теперь по поводу объемов.

Во-первых, не могу представить реальной ситуации, где действительно нужно обработать такую выборку. Конечный потребитель (человек) просто не воспримет "миллион контрагентов". Т.е. наверняка "масштаб" выборки можно будет укрупнить, что-то свернув. А если надо не по всем, а по одному/нескольким - то же самое, у вас 300 млн доков на 1 млн контрагентов - всего 300 доков на контрагента, не так уж и много.

Во вторых, при таких объемах для подобных задач рулят уже другие системы (а-ля OLAP) и другие подходы (промежуточные хранилища данных, заранее свернутая аналитика и итоги по периодам), которые выходят за рамки 1С.

Ну и в третьих, такие объемы, да на 1С - это опять же исключение. Штучные экземпляры. В массе для обычной фирмы-пользователя 1С база 20 гиг - это уже "ого-го". А там где больша - часто практикуется "закрытие периода".
Ответили: (117) (116) (115) (110)
# Ответить
109. Алексей 11.12.2009 11:22
(107) Речь исходно идет именно об SQL версии. К тому же ДБФ такие объемы и не снились.

И, кстати, "в ДБФ цикл выполняется по таблице" тоже неверно - это разве что в простейшем случае, типа ВыбратьЭлементы()/получитьЭлемент(). Для н/итогов (да и просто итогов :) ) всяко некая промежуточная выборка должна быть построена.
# Ответить
110. Алексей 11.12.2009 11:35
+ к (108) да, и забыл еще раз упомянуть - циклы ведь можно делать и на сервере! Правда, не знаю можно ли это делать через 8ку, подозреваю что нет.
Ответили: (123)
# Ответить
111. Ish_2 11.12.2009 12:28
(107) Конечно. Термин "семерочный" применен для удобства.
На самом деле речь идет о применении оператора "цикл" или о шаблоне мышления программистов СУБД гораздо более старом чем "семерка" .
Суть этого шаблона в том , что с таблицами нужно работать , перебирая записи явно в цикле (т.е. сканируя таблицу). Я же считаю , что это очень дурной тон тогда , когда можно обойтись агрегатными командами или запросами.
Например, в FoxPro решая такую задачу , можно обойтись без циклов и запросов , а только используя агрегатную командe Replace .

Отступление. Привычным и понятным для 1с-ника , например при расчете зарплаты, является подход , реализованный в тип.конф-иях :
позиционируемся на первую запись таблицы - Сотрудник и для него начинаем применять те или иные расчеты , позиционируемя на след . Сотрудника и так далее. На мой взгляд , боле правильным и выгодным подходом для СУБД является следующий : Берем таблицу "Сотрудники" и последовательно к ней применяем Первый расчет (для всей таблицы) , потом Второй расчет и т.д.
Другими словами алгоритм представляет собой последовательность получения временных таблиц. Правда для 1с-ника построение такой БД будет выглядеть диковато, но для специалиста по базам данных - нормально.
В СУБД , проще говоря, нужно стремиться оперировать не записями, а таблицами.
Ответили: (119) (112)
# Ответить
112. Алексей 11.12.2009 13:47
(111)
Проблема в том, что работа со временными таблицами появилась если не ошибаюсь начиная с 8.1. Соответственно "берем ... и применяем первый расчет, второй" и т.д. было недоступно в типовом механизме.

Далее, в SQL (по крайней мере MS) нет возможности указать возвращаемый набор результатов. Т.е. нельзя выполнить в одном пакете формирование нескольких врем. таблиц (или табличных переменных), и что-то с них получить: вернется не последний select пакета, а все результаты (в т.ч. промежуточных insert'ов и update'ов). А механизм 1Ски отдаст только первую выборку из набора. Вот и приходится делать несколько пакетов. Но это ладно.

В SQL почему-то отсутствует ряд возможностей, которые вроде-бы хорошо востребованы. Те же н/итоги ("кумулятивное суммирование"); работа с иерархией (оператор with, введенный в стандарт только то ли в SQL2003, толи 2005 и поддерживаемый далеко не всеми); генерируюшие функции (например, нужно получить последовательность дней с ... по... - приходится извращаться. В постри хоть есть generate_series, но это уже вне стандарта).
Ответили: (122) (121)
# Ответить
113. Алексей 11.12.2009 13:52
А вот как можно (с извратом) сделать на MSSQL

--наши исходные данные
create table #t(i int,s int)
insert into #t values (1,100)
insert into #t values (2,200)
insert into #t values (4,400)
insert into #t values (3,300)
insert into #t values (5,500)
select * from #t

-- наш результат
create table #tt(i int primary key,s int,ss int)
insert into #tt(i,s) select i,s from #t


/* А вот тут прикол - обработка таблицы будет вестись в порядке ее
первичного ключа. Вот такой неявный цикл.
Это не специфицировано в стандарте, это особенность реализации от MS.*/

declare @d int
set @d=0
update #tt set @d=@d+s, ss=@d

--окончательный результат
select * from #tt
Ответили: (124) (114)
# Ответить
114. Ish_2 11.12.2009 14:03
(113) Странно. На почту какие-то приходят соощения , какие-то нет. Отвечу чуть позже.
# Ответить
115. Ish_2 11.12.2009 15:19
(108)
"Акцентирую Ваше внимание еще раз: в начальной постановке пропущено (точнее, указано вне основной части и как то вскользь) критическое условие: мы не просто строим н/итоги, мы ФИЛЬТРУЕМ по н/итогу. В таком случае - да, от того где выполняется построение итогов зависит объем пришедшей на клиента выборки, и клиент начинает иметь значение."

Честно говоря, не очень понял.
В приложении написано , что нарастающие итоги для каждой записи (СуммаДо,СуммаПосле) строятся для того, чтобы определить запись для которой СуммаДо < ИскомыйПараметр <= СуммаПосле. Судя по всему Вы под этим понимаете фильтрацию по нарастающим итогам.

НО. При 2 варианте в начале статьи (ish_2) никакой фильтрации нет вовсе.
Делается запрос по всем движениям всех контргаентов и используется выборка Запрос.Выполнить().Выбрать(). И затем сканируя двухуроневую (контргаент,движения) выборку в цикле будем накапливать итог (сумма всех пред.движений) для каждого контргаента и сранивать этот итог с текущим долгом каждого контрагента.
# Ответить
116. Александр Медведев 11.12.2009 15:26
(108) по поводу объемов. Действительно свыше 100 контрагентов уже сложно воспринимать - для этого нужны агрегированные показатели. Например, просроченная дебиторка(не буду углублятся, но для этого тоже нужны нарастающие итоги) по менеджерам. Выходная таблица небольшая, но анализируемый объем данных огромный.
# Ответить
117. Ish_2 11.12.2009 15:36
(108) В целом согласен.
Но интересен эксперимент , который всё расставит по местам : с какого размера таблицы вариант 3(Anig99) превзойдет вариант 2 (Ish_2) по быстродействию ?

1. Пока установлен только факт Вариант 1( Eugeneer) значительно проигрывает по быстродействию Варианту 3(Anig99) на базе 120Гб.
Информация о этом факте представлена Anig99.

2. По информации того же Anig99, времена выполнения Варианта2(ish_2) и Варианта 3(Anig99) на этой же базе 120Гб относятся как 5:1
Ответили: (118)
# Ответить
118. Александр Медведев 11.12.2009 15:41
(117) я уже в личке говорил, теперь так озвучу, так как не успел к желаемому сроку... Пишу сейчас в свободное время обработку для тестирования времени получения нарастающих итогов разных подходов для разных объемов данных.
Ответили: (120)
# Ответить
119. hogik 11.12.2009 16:12
(111)
"Я же считаю , что это очень дурной тон тогда , когда можно обойтись агрегатными командами или запросами."
Именно об этом я и сказал в той юмористической теме. Т.е цель - писать красивые "запросы" (алгоритмы)... ;-) И "суть этого шаблона в том ", что за красотой не видна сама задача и пути её решения. Повторю, что "проблемы", обозначенной в Вашей статье, вообще не существует при наличии подходящих инструментов. Очень жаль, что "1С 8.х" таких инструментов не предоставляет... :-(
P.S. Не ставлю минус на данную публикацию, т.к. минус надо ставить не на Вашу публикации, а на "1С 8.х".
Ответили: (120)
# Ответить
120. Ish_2 11.12.2009 16:34
(118),(119)
Очень хорошо , что ты пишешь тест сравнивающий разные подходы !
Текущей статье не хватает замеров производительности , о которой писал еще Игорь в (21) . Без такого фактического сравнения можно еще долго спорить о "красивости" и "некрасивости" алгоритмов.

С Вами , Владимир , я опять не согласен. И ничего такого в минусе от Вас на текущую тему не вижу.
# Ответить
121. Ish_2 11.12.2009 22:42
(112)
Далее, в SQL (по крайней мере MS) нет возможности указать возвращаемый набор результатов. Т.е. нельзя выполнить в одном пакете формирование нескольких врем. таблиц (или табличных переменных), и что-то с них получить: вернется не последний select пакета, а все результаты (в т.ч. промежуточных insert'ов и update'ов). А механизм 1Ски отдаст только первую выборку из набора. Вот и приходится делать несколько пакетов. Но это ладно.
Странный абзац. В 1с Пакет запросов состоящий из нескольких запросов исполнен может быть двумя способами :
1. Запрос.Выполнить() - вернет результат последнего запроса в пакете.
2. Запрос.ВыполнитьПакет() - вернет массив содержащий результаты всех запросов , входящих в пакет.
# Ответить
122. Ish_2 11.12.2009 22:56
(112) Для меня в первую голову непонятно почему в 8.х для временных таблиц невозможны команды создания и модификации таблиц (create table, update). Целостность основной базы при реализации такой возможности не нарушается . И как бы тогда выглядела задача нарастающих итогов и просроченных долгов ?
В чем тут дело сказать трудно. Ведь и сами временные таблицы - тоже совершенно очевидная вещь - появились только через 4(!) года в 8.1, а до этого в 8.0 писались километровые вложенные запросы.
Ответили: (125)
# Ответить
123. Ish_2 11.12.2009 23:19
(110) В языке запросов 1с "цикла" точно нет.
Ответили: (125)
# Ответить
124. Ish_2 11.12.2009 23:28
/* А вот тут прикол - обработка таблицы будет вестись в порядке ее
первичного ключа. Вот такой неявный цикл.
Это не специфицировано в стандарте, это особенность реализации от MS.*/
declare @d int
set @d=0
update #tt set @d=@d+s, ss=@d
--окончательный результат
select * from #tt


(113) Виноват , не понял в чем прикол ? Если мы создали tt с первичным ключом , то ,разумеется, модификация таблицы tt по команде
update #tt set @d=@d+s, ss=@d
будет вестись в порядке ее первичного ключа. Тут есть что-то прикольное ?
Ответили: (125)
# Ответить
125. alexqc 14.12.2009 11:30
(124) В SQL не специфицирован порядок обработки данных. Вообще классически таблицы рассматриваются как "НЕУПОРЯДОЧЕННЫЙ" набор. ПК (если есть) должен однозначно идентифицировать запись, но не является обязательным указанием порядка обработки. Обработка данных в порядке ПК - это расширение стандарта, сделанное в отдельных реализациях, но не факт что аналогичная конструкция будет работать в другом SQL-сервере. И, наконец, такая конструкция противоречит "декларативному" характеру языка.

(122) Серьезно??? В 8.1 нельзя менять врем. таблицы??? А как они тогда вообще делаются - только через select into? А индексы на поля ставятся?
(Может, это просто разработчики вообще ничего кроме select не реализовали - а неизменение врем. таблиц - только следствие)
Я, признаться, думал что 8.1 позволяет делать все что можно с SQL.

(122) (123) Наверно нам надо четко указывать что имеем ввиду - 77 или 8. В 77 1С++ позволяет послать запрос в любом виде, но получает только 1-й набор пакета (таковы ограничения механизма семерки). Покольку я не работаю с 8кой, то не знаю ее возможностей и ограничений.
В любом случае, если в 8ке столько ограничений - толку от пакета никакого (точнее, пакет ничем не лучше последовательного выполнения неск. запросов).

Но речь шла не только о том, что нельзя получить результаты пакета кроме первого, а о том что вообще нельзя управлять выдачей результата. Т.е. если у меня в пакете есть "промежуточные" select,update,insert - то в результат попадет это все, хотя мне нужен только самый последний select. А нахрена лишние данные гонять? А уж тем более - зачем мне результат допустим insert'а?.
Ответили: (126)
# Ответить
126. Ish_2 14.12.2009 11:56
(125)
Серьезно??? В 8.1 нельзя менять врем. таблицы??? А как они тогда вообще делаются - только через select into? А индексы на поля ставятся?
(Может, это просто разработчики вообще ничего кроме select не реализовали - а неизменение врем. таблиц - только следствие)

Ага . Именно так.
К тому же сама возможность работы в 8.1 с временными таблицами ( в 8.0 этого не было) подавалось фирмой 1с - как большое достижение.
# Ответить
127. Ish_2 13.01.2010 12:38
(8),(17),(21),(27),(87),(88)
Господа , разрешите вас побеспокоить.
В продолжение темы "Подведем итоги . Нарастающие" я опубликовал отчет теперь уже для типовой конфигурации БП 1.6. http://infostart.ru/public/62899/
# Ответить
128. y-str 25.08.2011 10:04
Добрый день!

Создал новую публикацию (http://infostart.ru/public/88999/) с возможным альтернативным алгоритмом.
Милости прошу комментировать :)

---
С уважением,
Юрий Строжевский
# Ответить
129. 1с-программы.com 06.09.2012 15:20
Насколько я понимаю, предложенный тут вариант годится только для "размазывания" остатка долга на последние документы. На текущий момент мне интересен вариант решения похожей задачи, но чтобы было видно какой документ каким документом "закрылся". Это нужно для отчета по платежной дисциплине - чтобы было видно насколько своевременно происходили оплаты. Пока что решил задачу так: 1) Запрос к базе с получением дебетовых и кредитовых оборотов с детализацией до регистратора; 2) Цикл по "сопоставлению" дебета и кредита; 3) Запись результата сопоставления в регистр сведений; 4) Построение различных отчетов (в т.ч. по просроченной дебиторке) по регистру сведений.
Запрос получающий данные не совсем оптимальный для данной задачи, но взял его готовый из своего отчета по просроченной дебиторке - получает данные секунд 15. Цикл разнесения отрабатывает очень быстро - порядка 3 секунд. Получаем набор записей регистра сведений порядка 130 тыс строк - пишется долго - около 20 секунд (наверное сервер все таки не очень быстрый у клиента).
Ответили: (130) (131)
# Ответить
130. 1с-программы.com 06.09.2012 15:25
(129) Приведенные замеры времени для вызова на клиенте. На самом деле все это вынес в регламентное задание - время выполнения на стороне сервера не засекал (по идее должно быть быстрее т.к. не надо данные туда-сюда гонять). Но все же интересно можно ли решить не циклом а запросом ?
P.S.: Данные по оплаченности документов реализации также потом используются для отчета по оплаченной реализации с детализацией до номенклатуры.
# Ответить
131. Ish_2 08.09.2012 12:23
(129) С точки зрения программиста задача просроченного долга может иметь несколько вариантов решения.
Варианты эти могут быть сложные или простые , плохие или хорошие..
Но с точки зрения Заказчика ,как мне недавно объяснили, единственным правильным подходом
является следующий : организовать учет по расчетным документам, т.е использовать 3 субконто на счете 62 в БП2.0. Все проблемы тогда решаются сами собой.
Ответили: (132)
# Ответить
132. 1с-программы.com 09.09.2012 21:42
(131) Самым правильным вариантом несомненно является вариант учета по расчетным документам. Однако заказчик далеко не всегда хочет как правильно. Когда я был моложе, я старался убедить заказчика как именно правильно. Однако с возрастом появился вопрос "зачем". Сейчас я стараюсь дать заказчику именно то что он хочет и совершенно неважно (ни для него ни для меня) правильно это или нет. В итоге все остаются довольны (и заказчик и я) :-)
Ответили: (133)
# Ответить
133. Ish_2 09.09.2012 23:44
(132) Я еще молод,поэтому не упускаю случая , чтобы сказать Заказчику как правильно.
+ 1 [ hogik; ]
# Ответить
Внимание! За постинг в данном форуме $m не начисляются.
Внимание! Для написания сообщения необходимо авторизоваться
Текст сообщения*
Прикрепить файл






IE 2016