Порождающий запрос

Иногда в запросе необходимо получить искусственную таблицу заданного размера, не связанную с данными информационной базы. Эта получаемая «из воздуха» таблица может быть заполнена, например, числами натурального ряда или функционально связанными с ними значениями. Такая таблица может пригодится как временная таблица в запросе для соединения с реальными таблицами. Другой вариант – быстрое получение таблиц значений заданного размера, списков, массивов и прочее. В последних версиях MS-SQL есть возможности непроцедурной генерации таблиц посредством специального «итеративного» описания. Ну а для 1С пригодится следующее решение:

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

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

ВЫБРАТЬ 0 КАК Х
ПОМЕСТИТЬ Регистр1
ОБЪЕДИНИТЬ
ВЫБРАТЬ
1
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ Младшие.Х + 2 * Старшие.Х КАК Х
ПОМЕСТИТЬ Регистр2
ИЗ Регистр1 КАК Младшие, Регистр1 КАК Старшие
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ Младшие.Х + 4 * Старшие.Х КАК Х
ПОМЕСТИТЬ Регистр4
ИЗ Регистр2 КАК Младшие, Регистр2 КАК Старшие
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ Младшие.Х + 16 * Старшие.Х КАК Х
ПОМЕСТИТЬ Регистр8
ИЗ Регистр4 КАК Младшие, Регистр4 КАК Старшие
;
///////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ Младшие.Х + 256 * Старшие.Х КАК Х
ПОМЕСТИТЬ Регистр16
ИЗ Регистр8 КАК Младшие, Регистр8 КАК Старшие
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ Младшие.Х + 65536 * Старшие.Х КАК Х
ПОМЕСТИТЬ Регистр20
ИЗ Регистр16 КАК Младшие, Регистр4 КАК Старшие

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

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

Текст и его длина передаются в запрос как параметры. Для примера считаем, что длина текста ограничена миллионом символов. Вот текст концовки этого запроса. 

 

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ ПОДСТРОКА(&Текст, Х, 1) Символ, КОЛИЧЕСТВО(Х) КАК Частота
ИЗ Регистр20
ГДЕ Х МЕЖДУ 1 И &ДлинаТекста
СГРУППИРОВАТЬ ПО ПОДСТРОКА(&Текст, Х, 1)

Его начало такое же как на предыдущем рисунке. Интересно то, что этот метод работает быстрее, чем обработка в оперативной памяти. И сразу дает табличный результат! Например, первый мегабайт романа "Война и мир" обрабатывается в памяти 8,2 сек, а запросом — 4 секунды!

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

Определение частоты слов запросом оказалось совсем не тривиальной задачей. Вот решение:

 

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ Младшие.Х + 256 * 256 * Средние.Х + 256 * 256 * 2 * Старшие.Х КАК Х
ПОМЕСТИТЬ Регистр21
ИЗ Регистр16 КАК Младшие, Регистр4 КАК Средние, Регистр1 КАК Старшие
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ Х КАК У
ПОМЕСТИТЬ Разделители
ИЗ Регистр21
ГДЕ (НЕ ПОДСТРОКА(&Текст, Х, 1) ПОДОБНО "[а-я]") И Х МЕЖДУ 1 И &ДлинаТекста
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ Х, ВЫБОР КОГДА Х = 0 ТОГДА ИСТИНА КОНЕЦ КАК Нулевой, ВЫБОР КОГДА Х > 0 ТОГДА Х КОНЕЦ КАК Длина
ПОМЕСТИТЬ Интервалы
ИЗ Регистр4
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ У — Х КАК Начало, МИНИМУМ(Длина) КАК Длина
ПОМЕСТИТЬ УказателиСлов
ИЗ Разделители, Интервалы
СГРУППИРОВАТЬ ПО У — Х
ИМЕЮЩИЕ МАКСИМУМ(Нулевой) = ИСТИНА И МИНИМУМ(Длина) > 1
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ ПОДСТРОКА(ПОДСТРОКА(&Текст, Начало + 1, Длина — 1), 1, 15) КАК Слово, КОЛИЧЕСТВО(Начало) КАК Частота
ИЗ УказателиСлов
СГРУППИРОВАТЬ ПО ПОДСТРОКА(ПОДСТРОКА(&Текст, Начало + 1, Длина — 1), 1, 15)

К статье прилагается файл отчета, содержащий этот запрос. С его помощью в тексте первой части "Войны и мира" была определена частота слов за 24 секунды! А это примерно 1,5 миллиона символов! Правда, если использовать "кодинг", на чистом 1С можно решить ту же задачу примерно в два раза быстрее.

В качестве неочевидного применения предложенного запроса приводится пример расчета в запросе квадратного корня от числа в диапазоне 0 — 1 048 576. Вернее, целой части этого корня.

 

////////// создается таблица с числами от 0 до 1024 ////////////////////////////
ВЫБРАТЬ 0 КАК Х ПОМЕСТИТЬ Регистр1 ОБЪЕДИНИТЬ ВЫБРАТЬ 1
;
ВЫБРАТЬ Младшие.Х + 2 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр2
ИЗ  Регистр1 КАК Младшие,   Регистр1 КАК Старшие
;
ВЫБРАТЬ Младшие.Х + 4 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр4
ИЗ  Регистр2 КАК Младшие, Регистр2 КАК Старшие
;
ВЫБРАТЬ Младшие.Х + 16 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр8
ИЗ  Регистр4 КАК Младшие, Регистр4 КАК Старшие
;
ВЫБРАТЬ Младшие.Х + 256 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр10
ИЗ  Регистр8 КАК Младшие, Регистр2 КАК Старшие
;
////////// для проверки создается таблица с различными значениями аргумента ////
ВЫБРАТЬ 123456 КАК У ПОМЕСТИТЬ Аргументы
ОБЪЕДИНИТЬ ВЫБРАТЬ 555555
ОБЪЕДИНИТЬ ВЫБРАТЬ 987654
;
////////// формируется таблица, содержащая аргумент и значение функции /////////
ВЫБРАТЬ У, МАКСИМУМ(Х) КАК Квадратный_корень_Х
ИЗ Аргументы ЛЕВОЕ СОЕДИНЕНИЕ Регистр10 ПО (Х * Х < У)
СГРУППИРОВАТЬ ПО
У

 Аналогичным или похожим путем можно рассчитать и другие обратные функции. 

Похожим приемом в запросе можно получить "таблицу хаоса" — таблицу, которая содержит случайные числа. Например, следующая функция возвращает таблицу с заданным числом строк, содержащую случайные числа, равномерно распределенные в диапазоне 0 — 1.

function ChaosTable(N, Name = "СлучайноеЧисло") export

g = new RandomNumberGenerator();

q = new Query("select &r1 as r into t1 union select &r2;

             | select &k * a.r + b.r — cast((&k * a.r + b.r) / &M — 0.5 as number(10,0)) * &M as r into t2 from t1 as a, t1 as b;

             | select &k * a.r + b.r — cast((&k * a.r + b.r) / &M — 0.5 as number(10,0)) * &M as r into t4 from t2 as a, t2 as b;

             | select &k * a.r + b.r — cast((&k * a.r + b.r) / &M — 0.5 as number(10,0)) * &M as r into t8 from t4 as a, t4 as b;

             | select &k * a.r + b.r — cast((&k * a.r + b.r) / &M — 0.5 as number(10,0)) * &M as r into t16 from t8 as a, t8 as b;

             | select top " + Format(N, "NG=") + "

             | (&k * a.r + b.r) / &M — cast((&k * a.r + b.r) / &M — 0.5 as number(10,0)) as " + Name + " from t16 as a, t4 as b");

q.SetParameter("r1", g.RandomNumber()); q.SetParameter("r2", g.RandomNumber());

q.SetParameter("k", 1664525); q.SetParameter("M", 4294967295);

return q.Execute().Unload()

endfunction

Такая функция работает примерно в полтора раза быстрее, чем генерация случайных чисел для заполнения таблицы в цикле, а результат может использоваться прямо в запросе. В основе построения запроса лежит линейный конгруэнтный метод получения последовательности псевдослучайных чисел. Сложное выражение внутри запроса является ничем иным как нахождением остатка от деления на &M. К сожаления, непосредственно функции деления по заданному модулю в языке запросов нет.

Конечно, для использования в ответственных применениях потребуется проверка результата тестами NIST. Также было бы интересно исследовать использование для решения той же задачи метода Блюма-Блюма-Шуба. Запись запроса при этом будет еще короче.

 

Для удобства применения предложенного подхода на практике предлагается функция, которая формирует ТЕКСТ ЗАПРОСА или фрагмент пакетного запроса, выполнение которого приводит к получению временной таблицы, содержащей натуральный ряд чисел заданного размера. Вот текст этой функции

function ProtoText(N, M = 1000000000) export

    return ?(N > 2

    , ProtoText(M — Int(M — Sqrt(N)))

    + strreplace(strreplace(";select top #2 a.X * #1 + b.X X into r#2 from r#1 a, r#1 b; drop r#1", "#2", format(N, "NG=")), "#1", format(M — Int(M — Sqrt(N)), "NG="))

    , "select 0 X into r2 union select 1")

endfunction

Функция рекурсивная, параметр M — служебный (используется для сокращения записи функции). Результирующая временная таблица имеет имя r{ЗаданныйРазмер}.

88 Comments

  1. ildarovich

    Иногда в запросе необходимо получить искусственную таблицу заданного размера, не связанную с данными информационной базы. Эта получаемая «из воздуха» таблица может быть заполнена, например, числами натурального ряда или функционально связанными с ними значениями. Такая таблица может пригодится как временная таблица в запросе для соединения с реальными таблицами. Другой вариант – быстрое получение таблиц значений заданного размера, списков, массивов и прочее. В последних версиях MS-SQL есть возможности непроцедурной генерации таблиц посредством специального «итеративного» описания. Ну а для 1С пригодится следующее решение:

    Перейти к публикации

    Reply ↓
  2. O-Planet

    Впечатлила аватарка. Уже сразу решил плюсануть, не читая. Но почитал. Задача такая возникала. Про таблицу с битами не додумался тогда. Зачет.

    Reply ↓
  3. Jogeedae

    это очень сильное колдунство! 🙂

    3000чертей!

    повторил запрос, 1с-серв всю память сьел и подавился, а предприятие зависло… предупреждать надо!! :(((

    кстати, для создания ТЗ определённого размера можно использовать COMSafeArray

    Reply ↓
  4. IgorI

    Хоть идея и совершенно простая, но реализовать это в запросе… Спасибо за наводку!

    Reply ↓
  5. i132

    Если создавать таблицу занчений с одинаковыми строками, можно поигратьса со ЗначениемИзСтрокиВнутр(),

    Например Сохранить в строку таблицу значений с одной строкой а потом в цикле вставлять перед окончанием эту строку…

    Reply ↓
  6. ildarovich

    (2) Видимо, было мало оперативки, в таком случае ожидаемы и проблемы с формированием ТЗ из миллиона строк.

    Важен принцип, а конкретный запрос приведен для примера и оценки скорости (замеры делались на ноутбуке в файловом варианте базы).

    По аналогии можно формировать и меньшие таблицы.

    Если их размер не равен степеням двойки, используем условие ГДЕ X < &ЗаданныйРазмер.

    За напоминание о COMSafeArray спасибо!

    (4) Запрос из http://infostart.ru/public/68269/ я видел,

    хотя за основу брал свое же решение из http://forum.infostart.ru/forum14/topic35991/message400742/#message400742 (внешнего сходства немного, но общая «математика»).

    Отличие от http://infostart.ru/public/68269/ я вижу в том, что:

    1) оно нацелено не только на даты (кроме того, что уже сказано, например, на основе этого запроса можно подбором находить обратные функции, не вычисляемые в запросе, типа квадратного корня и прочих);

    2) оптимизировано по времени выполнения за счет соединения таблицы с собой (различные варианты сравнивались).

    (5) Цикл из миллиона повторений сразу сделает этот прием неконкурентоспособным, а вот если все время удваивать подстроку — может и получиться…

    Reply ↓
  7. Oleg_nsk

    Я подобное так делал:

    Запрос.Текст = «ВЫБРАТЬ
    | 0 КАК Бит
    |ПОМЕСТИТЬ Регистр
    |
    |ОБЪЕДИНИТЬ ВСЕ
    |
    |ВЫБРАТЬ
    | 1
    |;
    |
    |////////////////////////////////////////////////////////////­////////////////////
    |ВЫБРАТЬ
    | Н10.Бит + 2 * Н9.Бит + 4 * Н8.Бит + 8 * Н7.Бит + 16 * Н6.Бит + 32 * Н5.Бит + 64 * Н4.Бит + 128 * Н3.Бит + 256 * Н2.Бит + 512 * Н1.Бит + 1024 * Н0.Бит + 2048 * Н11.Бит КАК Сумма
    |ИЗ
    | Регистр КАК Н11,
    | Регистр КАК Н10,
    | Регистр КАК Н9,
    | Регистр КАК Н8,
    | Регистр КАК Н7,
    | Регистр КАК Н6,
    | Регистр КАК Н5,
    | Регистр КАК Н4,
    | Регистр КАК Н3,
    | Регистр КАК Н2,
    | Регистр КАК Н1,
    | Регистр КАК Н0″

    Показать

    Reply ↓
  8. ildarovich

    (7) Проверял, работает медленнее, кроме того, удобнее писать

    Н10.Бит + 2 *(Н9.Бит + 2 * (Н8.Бит + 2 * (Н7.Бит + 2 * (Н6.Бит + 2 * (Н5.Бит + 2 * (Н4.Бит + 2 * (Н3.Бит + 2 * ( Н2.Бит + 2 * (Н1.Бит + 2 * (Н0.Бит + 2 * Н11.Бит)))))))))) 
    Reply ↓
  9. cool.vlad4

    (5) Ага, я также и массив заполняю, изменяю.(0) +++ 😀

    Reply ↓
  10. cool.vlad4

    (6)

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

    А там можно Формат использовать, для получения строки

    Reply ↓
  11. Famza

    Любопытно…А в каком практическом решении такое использовалось? 🙂

    Reply ↓
  12. dkprim

    (11)присоединяюсь 🙂

    Reply ↓
  13. dkprim

    (11)присоединяюсь 🙂

    а вообще, понравилась идея и реализация. всегда нравится разбираться с такими задачами. интересно и занятно 🙂

    спасибо за предоставленное решение 🙂

    Reply ↓
  14. IgorI

    (4) А я и не предполагал, что это что-то уникальное. Но вот попалась на глаза именно эта статья.

    А Вам спасибо за «подборку» тематических статей. Обязательно посмотрю.

    Reply ↓
  15. ildarovich

    (11) Если Ваш вопрос к тому, что не хватает нескольких не абстрактных, а «приземленных» примеров использования, то я постараюсь привести еще несколько. Все же посмотрите внимательно на пример про извлечение квадратного корня. Как иначе вычислить расстояние в запросе? (вообще то есть еще один способ — быстрый, но не такой компактный).

    (14) Видимо, Вы что-то пропустили. Речь как раз идет о

    создали какую надо таблицу

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

    Reply ↓
  16. Angeros

    Ну и что… есть почти уже стандартный запрос для получения последовательности дат. А в чем у вас свежесть идеи???

    ВЫБРАТЬ
    0 КАК Цифра
    ПОМЕСТИТЬ ВсеЦифры
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    1
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    2
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    3
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    4
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    5
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    6
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    7
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    8
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    9
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(&ДатаНач, ДЕНЬ, ВсеЦифры4.Цифра * 1000 + ВсеЦифры3.Цифра * 100 + ВсеЦифры2.Цифра * 10 + ВсеЦифры1.Цифра * 1) КАК ДатаДень
    ПОМЕСТИТЬ ВсеДни
    ИЗ
    ВсеЦифры КАК ВсеЦифры1
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВсеЦифры КАК ВсеЦифры2
    ПО (ВсеЦифры2.Цифра * 10 + ВсеЦифры1.Цифра * 1 <= РАЗНОСТЬДАТ(&ДатаНач, КОНЕЦПЕРИОДА(&ДатаКон, ДЕНЬ), ДЕНЬ))
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВсеЦифры КАК ВсеЦифры3
    ПО (ВсеЦифры3.Цифра * 100 + ВсеЦифры2.Цифра * 10 + ВсеЦифры1.Цифра * 1 <= РАЗНОСТЬДАТ(&ДатаНач, КОНЕЦПЕРИОДА(&ДатаКон, ДЕНЬ), ДЕНЬ))
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВсеЦифры КАК ВсеЦифры4
    ПО (ВсеЦифры4.Цифра * 1000 + ВсеЦифры3.Цифра * 100 + ВсеЦифры2.Цифра * 10 + ВсеЦифры1.Цифра * 1 <= РАЗНОСТЬДАТ(&ДатаНач, КОНЕЦПЕРИОДА(&ДатаКон, ДЕНЬ), ДЕНЬ))

    Показать

    Reply ↓
  17. ildarovich

    В (17) и (7) делается примерно одно и то же. Создается исходная таблица из 10-ти или 2-х строк и во вторм запросе пакета производится 2 или 9 соединений для получения таблицы из 1000 строк.

    «Первая свежесть» идеи (0) в том, чтобы минимизировать число соединений на всех этапах получения искусственной таблицы любого заданного размера и, таким образом, ускорить ее построение. Для этого обеспечивается квадратичный рост размера получаемой таблицы 2 — 4 — 16 — 256 — 65536 — … На каждом этапе размер возводится в квадрат за одно соединение. Это похожий, но другой, более быстрый принцип (проверял, сравнивал)!

    Во-вторых, я предлагаю использовать получаемые таблицы не только для генерации дат в заданном диапазоне, но и для быстрого (проверено!) формирования больших таблиц значений, массивов, списков; для вычисления обратных функций, которых нет в языке запросов; для решения других задач, примеры которых я еще приведу. То есть «вторая свежесть идеи» заключается в обобщении подхода с использованием искусственно-порожденных таблиц, в использовании его для решения других задач.

    Reply ↓
  18. Fragster

    Делал подобное через таблицу из чисел от 0 до 9 и соединением ее самой с собой с множителем «10» несколько раз (кстати, последоватеьлное соединеине не нужно, можно все в одном:

    ВЫБРАТЬ
    0 КАК б
    ПОМЕСТИТЬ Т
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    1
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    Т0.б + 2 * Т1.б + 4 * Т2.б + 8 * Т3.б + 16 * Т4.б + 32 * Т5.б + 64 * Т6.б + 128 * Т7.б КАК Числа
    ИЗ
    Т КАК Т0,
    Т КАК Т1,
    Т КАК Т2,
    Т КАК Т3,
    Т КАК Т4,
    Т КАК Т5,
    Т КАК Т6,
    Т КАК Т7
    
    УПОРЯДОЧИТЬ ПО
    Числа

    Показать

    )

    Reply ↓
  19. ildarovich

    (19) Это такое же по сути решение, как в (7) и (17). Я предлагаю другое решение, потому что метод «все в одном» работает медленнее (проверял, пробовал)! У него («все в одном») больше соединений! В этом вся суть!

    В Вашем варианте для получения таблицы из миллиона записей потребуется 19 соединений (число волшебно совпадает с номером Вашего поста), а в моем — 5! 19 и 5 — есть разница? То есть это не просто разная запись, это другой принцип. И, как вижу, все же не очевидный, поскольку столько людей не увидели разницы.

    Кстати, в моем варианте (19) используется запись, не требующая знания ряда степеней двойки:

    Т0.б + 2 * (Т1.б + 2 * (Т2.б + 2 * (Т3.б + 2 * (Т4.б + 2 * (Т5.б + 2 * (Т6.б + 2 * Т7.б)))))).

    Извините, что вынужден повторятся. Вижу, что предыдущие комментарии не читаются.

    Reply ↓
  20. sinichkas

    очень удобная весч,спасибо

    Reply ↓
  21. ildarovich

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

    Reply ↓
  22. dimanich70

    Побольше бы примеров, как это можно использовать в повседневной работе. А так за не тривиальность плюсую. Раньше про такой метод не читал.

    Reply ↓
  23. sound

    Прикольненько

    Reply ↓
  24. hogik

    (0)

    «Например, первый мегабайт романа «Война и мир» обрабатывается в памяти 8,2 сек, а запросом — 4 секунды!»©

    Сергей.

    И это не «запрос» молодец, а интерпретатор/компилятор 1С-а бяка. 😉

    Проверил алгоритм в памяти на «1С 7.7».

    Если исходные данные в строке — 1249 сек.

    Если данные в массиве — 2 сек.

    Ну, а перегон из строки в массив занял 1215 сек.

    Любопытно, что строка в 100000 символов обрабатывается за 12 сек.

    А на С++ алгоритм выполняется — 0,00253 сек.

    Reply ↓
  25. Поручик

    (0) А нельзя ли текст запросов текстом публиковать, а не рисунками.

    Reply ↓
  26. ildarovich

    (26) Тексты запросов в файлах, прилагаемых к публикации.

    Я пробовал «разукрашивать» тексты, но у меня потом форматирование разъезжается, решил, что рисунки проще.

    Reply ↓
  27. Поручик

    (27) Разукрашивал этим http://infostart.ru/public/19856/ ? Люди пользуются, ничего не разъезжается.

    Reply ↓
  28. ildarovich

    (25) Конечно, это так. Все, что можно сделать одной инструкцией, 1С делает гораздо быстрее. И тут фактически мы заставляем выполнить (через запрос и язык запросов) некоторые сложные действия одной инструкцией Запрос.Выполнить(). Получается быстрее. Это стандартный прем оптимизации — найти одну инструкцию.

    Правда, меня удивляют приведенные Вами данные. Разбор строки (определение частот) из миллиона символов в оперативной памяти занимает в 8-ке 8,2 секунды (использовал соответствия, запись в одну строку, отключенный отладчик). Неужели 7-ка настолько медленнее? Как-то не верится.

    Reply ↓
  29. ildarovich

    (28) Попробую.

    Reply ↓
  30. hogik

    (29)

    «Неужели 7-ка настолько медленнее? Как-то не верится.»(с)

    Сергей.

    Я тщательно проверял свой текст алгоритма. 😉

    Думаю, время со строкой в 1000000 — это, типа, глюк.

    Скорости для строк:

    1 000 000 байт — 1249 сек.

    100 000 байт — 12 сек.

    10 000 байт — 0.157 сек.

    1 000 байт — 0.005 сек.

    И, вообще, в семерке много подобных «странностей»… 🙂

    Reply ↓
  31. onyx

    Понравилась идея и реализация. всегда нравится разбираться с такими задачами. интересно и занятно 🙂

    спасибо за предоставленное решение 🙂

    Reply ↓
  32. hogik

    (29)

    Сергей.

    Я напоминаю себе, возней с «семеркой», персонажа:

    «Неуловимый Джо — персонаж известного анекдота; обозначает человека или явление, всем известного, но при этом никому не нужного.»(с)

    Я выяснил. 🙂

    В «семерке» время выполнения функции Сред(Строка,Позиция,1) линейно зависит от длины исходной строки (первого аргумента). Т.е. эта функция, как бы принимает не адрес строки, а — значение. Блеск… 🙂 Интересно, а как в «восьмерке» работает такая функция?

    Reply ↓
  33. ildarovich

    (33) В восьмерке эта функция работает достаточно быстро. Вот такой цикл

    Цикл Для ё = 1 По 1048576 Цикл ж = Сред(Текст, ё, 1); Частота[ж] = ?(Частота[ж] = Неопределено, 0, Частота[ж] + 1) КонецЦикла

    выполняется 8,2 секунды, а в нем есть еще чтение и запись соответствия.

    Про трудности работы с длинными строками в 77 говорилось в одной из здешних публикаций по оптимизации кода в 77. Там предлагалось разбивать строки перед обработкой.

    Reply ↓
  34. hogik

    (34)

    Сергей.

    Рекомендации, типа, разбить строки — интересно. 🙂

    А разбивать строки — функцией Сред(), как это у меня сделано, например, в массив? 😉

    Времена см. в (25) сообщении. Суммарное время выполнения останется прежним. Нет — это не выход. Печально, еще и то, что если написать подобные функции на ВК, то очень большие накладные расходы на вызов методов. Например, метод Х=Lib.DeleteStr(«*»,1,1) для 100000 вызовов выполняется 160 секунд. А этот метод, всего, что и делает — из строки в один байт удаляет первый символ и возвращает строку нулевой длины. Еще смешней. Время просмотра таблицы в 2700000 циклом — 30 секунд. Но, если в этом цикле выполнять присвоение полей таблицы в рабочие переменные (15 штук, средняя длина поля — 10 байт), то время становится — 140 секунд. А ведь все поля, после чтения записи, уже лежат в оперативной памяти. Вот такая жесть в «семерке»… 🙁 Я давно пишу «боевые» куски алгоритмов на С++ с минимальным количеством вызовов методов ВК. Т.е. «максимально-целиком» загоняю алгоритм в С++.

    Вот… (с)

    Reply ↓
  35. jjinn

    спс

    Reply ↓
  36. zhleonid8

    спамеры

    Reply ↓
  37. alexk-is
    Reply ↓
  38. vec435

    полезная публикация

    Reply ↓
  39. ildarovich

    (38) Очень интересно! — Если можете, приведите численные результаты замеров для SQL.

    Потом, возможно, стоит посмотреть:

    0) результаты для (7) и (19), то есть с использованием основания 2;

    1) диапазоны до 65536 и более миллиона;

    2) вариант с (0), когда начальная таблица — это Регистр4 (выбрать 0 — 15 поместить регистр4).

    Это для того, чтобы понять, что влияет больше: число соединений (у (0) и (38) оно одинаково! и, думаю, это главное) или время трансляции запроса в SQL или необходимость фиксации временных таблиц.

    Тогда и можно будет сделать выводы о сравнительной применимости (0) и (38) как подходов к формированию искусственных таблиц.

    Reply ↓
  40. alexk-is

    (40) Время замеров в секундах. Результат запросов 1000000 записей.

    Платформы 8.1.15.14 и 8.2.14.533.

    (0)

        8.1   8.2

    Ф   2.4   1.3

    С   3.4   2.1

    (38)

        8.1   8.2

    Ф   3.8   2.0

    С   2.9   1.9

    (0) + оптимизация

        8.1   8.2

    Ф   1.9   1.2

    С   3.1   2.1

    (38) + оптимизация

        8.1   8.2

    Ф   2.9   1.9

    С   2.7   1.7

    Reply ↓
  41. ildarovich

    (41) Большое спасибо! — А что такое «+ оптимизация»?

    Также уточню гипотезу из (40): Кажется, что подход (38) выигрывает у подхода (0) только в узком диапазоне условий, когда число соединений в запросах получается одинаковым. Под подходами я имел ввиду формирование искусственной таблицы любого заданного размера «взрывным» способом «порождающего запроса» (0), либо линейно-нарастающим числом соединений как в (38).

    Reply ↓
  42. alexk-is

    (42) Ничего особенного. Поправил запрос, чтобы при тех же результатах он работал быстрее.

    Reply ↓
  43. ildarovich

    Добавлен пример запроса, разбивающего текст на слова и определяющего частоту слов текста. Для обработки 1,5 миллиона символов текста романа «Война и мир» запросом понадобилось 24 секунды!

    Reply ↓
  44. alexk-is

    (0) Код картинками — ну, это со зла, со зла…

    Reply ↓
  45. ildarovich

    (45) Уже обещал — переделаю в ближайшее время.

    Reply ↓
  46. ildarovich

    (45)(46) Переделал тексты запросов из картинок в раскрашенный текст

    Reply ↓
  47. qwerty_3

    Очень интересно, спасибо.

    Reply ↓
  48. logos

    Огромное спасибо за полезную информацию

    Reply ↓
  49. ildarovich

    Добавил пример получения в запросе «таблицы хаоса» — таблицы, которая содержит случайные числа

    Reply ↓
  50. andrewks

    (51)

    Сложное выражение внутри запроса является ничем иным как нахождением остатка от деления на &M

    RandomNumber(), как известно, может вернуть 0. и вот если так случится, что и в r1, и в r2 придут нули — тогда ой. конструкция &N-cast(&N/&M-0.5 as number(10,0))*&M даст при N = 0 не N % M, а -M

    чтобы не городить case внутри запроса, думаю, проще «поднять» нижнюю границу через вызов RandomNumber(1)

    Reply ↓
  51. ildarovich

    (52) Спасибо! — Вы очень внимательны. Согласен. Хотя вероятность такого события и составляет 1 / (4294967295 * 4294967295), то есть меньше одной квинтиллионной, но подстраховаться предложенным Вами способом ничего не стоит, я сделаю это, когда в очередной раз буду обновлять статью.

    Reply ↓
  52. ildarovich

    Добавил функцию, формирующую ТЕКСТ ЗАПРОСА (может быть фрагментом пакетного запроса), формирующего искусственную таблицу заданного размера. Это должно быть очень практично: теперь не нужно заранее знать 31, 365 или больше дат (например) нужно получить в таблице — функция сформирует фрагмент запроса для любого заданного количества строк искусственной таблицы. Способ в целом тот же, но немного упрощен: например, таблица из 1000 строк получается перемножением таблиц из 34 строк, таблица из 34 строк — перемножением таблиц из 6 строк, таблица из 6 строк — перемножением таблиц из 3 строк, а она — перемножением таблиц из двух строк. То есть каждый раз вычисляется квадратный корень и ближайшее целое сверху к этому корню число — это и есть размер умножаемой таблицы.

    Reply ↓
  53. catena

    У вас подсчет частоты слов пропускает первое слово, если строка начинается не с пробела или другого символа. Надо в разделители добавить 0.

    А так с интересом прочитала. В третий раз, как оказалось 🙂

    Reply ↓
  54. ildarovich

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

    ВЫБРАТЬ Х КАК У
    ПОМЕСТИТЬ Разделители
    ИЗ Регистр21
    ГДЕ (НЕ ПОДСТРОКА(&Текст, Х, 1) ПОДОБНО «[а-я]») И Х МЕЖДУ 1 И &ДлинаТекста ИЛИ Регистр21.Х = 0
    ;

    При очередном обновлении поправлю в статье. Приятно вести обсуждение на уровне сути вопроса. А то иногда кажется, что в содержательной части некоторых статей никто разбираться и не старается. А так я бы добавил, что основной хитростью данного запроса является ограничение длины слов (в примере взято ограничение 16 знаков, хотя можно и больше). Именно это позволяет уйти от квадратичной зависимости времени работы запроса от длины текста.

    Reply ↓
  55. catena

    (56)Я просто люблю играться с запросами и всегда разбираю, если нахожу что-то интересное. Сохраняя этот запрос из консоли, увидела, что он у меня уже сохранен, да и плюс я оказывается уже ставила 🙂

    Reply ↓
  56. Al-X

    Спасибо за предоставленные алгоритмы! Убраю их в свою коллекцию….

    Reply ↓
  57. Synoecium

    По поводу алгоритма Блюм-Блюм-Шуба (BBS), автор по-видимому имеет ввиду подобный следующему запрос получения последовательности СЧ:

    ВЫБРАТЬ
    &x01 КАК x
    ПОМЕСТИТЬ t1
    
    ОБЪЕДИНИТЬ
    
    ВЫБРАТЬ
    &x02
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    (a.x + 2 * b.x) * (a.x + 2 * b.x) — (ВЫРАЗИТЬ((a.x + 2 * b.x) * (a.x + 2 * b.x) / &M — 0.5 КАК ЧИСЛО(10, 0))) * &M КАК x
    ПОМЕСТИТЬ t2
    ИЗ
    t1 КАК a,
    t1 КАК b
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    (a.x + 2 * b.x) * (a.x + 2 * b.x) — (ВЫРАЗИТЬ((a.x + 2 * b.x) * (a.x + 2 * b.x) / &M — 0.5 КАК ЧИСЛО(10, 0))) * &M КАК x
    ПОМЕСТИТЬ t4
    ИЗ
    t2 КАК a,
    t2 КАК b
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    (a.x + 2 * b.x) * (a.x + 2 * b.x) — (ВЫРАЗИТЬ((a.x + 2 * b.x) * (a.x + 2 * b.x) / &M — 0.5 КАК ЧИСЛО(10, 0))) * &M КАК x
    ПОМЕСТИТЬ t8
    ИЗ
    t4 КАК a,
    t4 КАК b
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    (a.x + 2 * b.x) * (a.x + 2 * b.x) — (ВЫРАЗИТЬ((a.x + 2 * b.x) * (a.x + 2 * b.x) / &M — 0.5 КАК ЧИСЛО(10, 0))) * &M КАК x
    ПОМЕСТИТЬ t16
    ИЗ
    t8 КАК a,
    t8 КАК b
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ ПЕРВЫЕ 100
    (a.x + 2 * b.x) * (a.x + 2 * b.x) / &M — (ВЫРАЗИТЬ((a.x + 2 * b.x) * (a.x + 2 * b.x) / &M — 0.5 КАК ЧИСЛО(10, 0))) КАК Результат
    ИЗ
    t16 КАК a,
    t4 КАК b

    Показать

    Reply ↓
  58. ildarovich

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

    Reply ↓
  59. Synoecium

    (60) я тоже сомневаюсь в качестве такой генерации, но такие же сомнения возникают по поводу вашего примера с линейным конгруэнтным методом. Там ведь также расходятся цепочки зависимостей от пар a,a;a,b;b,a;b,b. Сам алгоритм я делал как-то на с++, там это делается довольно просто и качество генерации высокое, поэтому стало интересно, как вы это представляете на языке запросов 🙂

    Reply ↓
  60. ildarovich

    (61) Вообще генерация случайных чисел — слишком большая тема, чтобы ее касаться так просто и мимоходом. Можно вспомнить и главы из «Исскуство программирования» Дональда Кнута и ERNIE 1 из лондонского музея науки. Данный запрос я написал под впечатлением от Keccak. Из его описания я понял, что еще есть место для проб и ошибок в данной области. Это — проба, а насколько это ошибка покажут практика и тесты.

    Reply ↓
  61. Synoecium

    Прошу меня извинить, но уж очень тема интересная 🙂

    Накидал запрос, который из находит значения корней из заданной таблицы аргументов. При x <= 1 млн, точность 3 знака после запятой. Работает довольно шустро, на ноутбуке 1000 значений считает за 0.2 сек:

    ВЫБРАТЬ
    &x
    ПОМЕСТИТЬ источник
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    источник.x / 2 КАК а,
    источник.x
    ПОМЕСТИТЬ т1
    ИЗ
    источник КАК источник
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    (((т1.а + т1.x / т1.а) / 2 + т1.x / ((т1.а + т1.x / т1.а) / 2))/2 + x/(((т1.а + т1.x / т1.а) / 2 + т1.x / ((т1.а + т1.x / т1.а) / 2))/2))/2 КАК а,
    т1.x
    ПОМЕСТИТЬ т2
    ИЗ
    т1 КАК т1
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    (((т2.а + т2.x / т2.а) / 2 + т2.x / ((т2.а + т2.x / т2.а) / 2))/2 +x/(((т2.а + т2.x / т2.а) / 2 + т2.x / ((т2.а + т2.x / т2.а) / 2))/2))/2 КАК а,
    т2.x
    ПОМЕСТИТЬ т3
    ИЗ
    т2 КАК т2
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    (((т3.а + т3.x / т3.а) / 2 + т3.x / ((т3.а + т3.x / т3.а) / 2))/2 +x/(((т3.а + т3.x / т3.а) / 2 + т3.x / ((т3.а + т3.x / т3.а) / 2))/2))/2 КАК а,
    т3.x
    ПОМЕСТИТЬ т4
    ИЗ
    т3 КАК т3
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    (((т4.а + т4.x / т4.а) / 2 + т4.x / ((т4.а + т4.x / т4.а) / 2))/2 + x/(((т4.а + т4.x / т4.а) / 2 + т4.x / ((т4.а + т4.x / т4.а) / 2))/2))/2 КАК а,
    т4.x
    ПОМЕСТИТЬ т5
    ИЗ
    т4 КАК т4

    Показать

    Reply ↓
  62. ildarovich

    (63) Все правильно. Формула Герона. Мне пришлось применить ее в обработке к статье «Как нарисовать граф на 1С«. Там вышло очень удачно, что итерации по уточнению корня можно делать ПАРАЛЛЕЛЬНО с работой основного алгоритма расчета перемещений. Поэтому хватило простой формулы (а + б/а)/2. До того, как я до этого додумался, приходилось, как и Вам, подставлять результаты итераций друг в друга. Но мне хватало трех итераций, поскольку в качестве начального приближения я брал сумму катетов. Так как задача была конкретная — рассчитать гипотенузу. Максимальная погрешность при таком подходе была 0,197 процента. За три итерации! Поэтому могу предложить в дополнение к Вашему безусловно правильному подходу, еще исходя из характера задачи выбирать начальное приближение. Тогда можно сэкономить итерации. Также в плане обмена опытом могу сказать, что при упрощении получающихся громоздких выражений полезно пользоваться сайтом http://www.wolframalpha.com/. Ну а подход, показанный в данной статье, конечно не быстрый, но зато универсальный.

    Reply ↓
  63. Synoecium

    (64) под формулой Герона вы наверное имеете ввиду формулу вида y=(c#k8SjZc9Dxk2+a#k8SjZc9Dxk2-b#k8SjZc9Dxk2)/2c, но что-то не улавливаю связи между ней и вычислением корня числа. А вообще в моем запросе используется частный случай метода Ньютона (еще известный как метод касательных Ньютона-Рафсона)

    x_(n+1)=x_(n)-f(x)/f'(x)

    в случае квадратного корня: x_(n+1)=0.5(x_(n)+N/x_(n)), полагаем что f(x)=x#k8SjZc9Dxk2-N

    Reply ↓
  64. ildarovich

    (65) Я имел ввиду ‘http://en.wikipedia.org/wiki/Methods_of_computing_square_roots’

    . В русской википедии тоже есть статья, но ссылку на нее не могу вставить, так как подчеркивание в названии обрезает ссылку — поищите поиском «Итерационная формула Герона». Получается, что это одно и тоже, поскольку в этой статье написано, что эту же формулу можно получить, применяя метод Ньютона к решению уравнения а — х#k8SjZc9Dxk2 = 0.

    Reply ↓
  65. Elisy

    (63) Пересмотрите, пожалуйста, вычисление начального значения источник.x / 2. К данной задаче подойдет метод грубой оценки. Можно посмотреть здесь: http://infostart.ru/public/204916/

    Reply ↓
  66. for_sale

    простите за глупый вопрос — а зачем нужна пустая таблица заданного размера? какой-то пример из жизни есть?

    Reply ↓
  67. ildarovich

    (68) Вообще-то таблица не совсем пустая, а с числами в заданном диапазоне.

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

    В статье Будни автоматизации или «мне нужна программка для 3D упаковки» с помощью таких таблиц генерируются варианты расположения коробок в коробе при 3D упаковке.

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

    В статье Агрегатное суммирование строк в запросе – сложно, но не невозможно эта таблица позволяет разбивать строки на символы.

    Ну а чаще всего такие таблицы вспоминают, когда нужно сформировать «календарь» — множество дат в заданном диапазоне.

    Все это реальные практические задачи.

    Reply ↓
  68. chmv

    Интересно

    Reply ↓
  69. ildarovich

    Нашлось еще одно применение для порождающего запроса. С его помощью можно получать готовый массив любого заданного размера N, содержащий последовательность чисел от 0 до N — 1. Этот массив затем, например, можно загрузить в нужную колонку таблицы значений, чтобы перенумеровать ее строки, не используя цикл. Такой способ всего примерно в 3 раза медленнее нумерации в цикле (для файловой базы).

    Все необходимые для решения этой задачи функции (prototext, ЧисловаяПоследовательностьТаблицей, ЧисловаяПоследовательностьМассивом) в силу их компактности приведены в статье Минимализмы.

    Reply ↓
  70. eugeniezheludkov

    я как то использовал подобные трюки на высоконагруженной системе, ммммалюсенький запрос который ничего не выбирал из таблиц ИБД, а только порождал данные быстрей чем в коде …. доооолго же мы не могли понять куда девается вся память, проц и канал связи на сервере с 16 гигами оперативы и 48 ядрами (точно не помню количество) при работе всего 40 пользователей, а вы представьте что ваш запрос запустят одновременно 40 человек, а не вы один в песочнице….. перенес все на клиентскую сторону (в код) и сервер вздохнул свободной грудью 🙂 данные у всех генерились разные уникальные исходя из входного параметра, с тех пор в 1с я никогда не юзаю запросы для длинных вычислений или генераций данных … нужно распределять нагрузку ! но если есть деньги на хороший сервер или это файловый вариант то конечно можно и побаловаться, в крайнем случае если нужно сгенерить много данных и быстрей чем позволяет 1С то можно через JS на клиенте через комобъекты, а если и этого не достаточно то GLPK.exe в макет (типа МАТЛАБ только Опенсорсный и работает как внешний интерпретатор с командной строки или файла, может вести расчеты на видеокарте) на клиенте

    Reply ↓
  71. ildarovich

    (72) eugeniezheludkov, «подобные трюки» — интересно было бы на них посмотреть (малюсенький запрос), чтобы оценить степень подобия. В данном случае ни на одном шаге данных не больше, чем нужно будет в итоге, поэтому вряд ли будет перегрузка по-сравнению с другими решениями.

    Но все же основное назначение данного метода — это не формирование таблиц для последующего использования вне запроса, а формирование таблиц для использования внутри запроса. Оказалось, что сформировать пустую таблицу значений с заданным числом строк или пронумерованную таблицу в коде все же несколько быстрее (если делать это правильно).

    Reply ↓
  72. eugeniezheludkov

    (73) сегодня постараюсь в истории хранилища откопать старые варианты функций, но вот навскидку нашел в коде одну из вешающих сервер в запросном варианте:

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

    это не порождающая функция, а анализирующая к сожалению , функция элементарная но именно она съедала кучу памяти и процессора пока выполнялась в виде запроса.. но у нас были и порождающие тоже постараюсь вспомнить как они выглядели и где применялись ранее (помню что по их результатам диаграмма ганта рисовалась нехилая ), чтоб не быть голословным … да и код я все-же удалю позже т.к подписывал «неразглашение» и все такое

    Reply ↓
  73. ildarovich

    (74) eugeniezheludkov, как я понял, запрос был в функции «получить секции». То есть типа того, что там генерировались все соседние секции и отсекались не пройденные? Но разве структура секций не хранится в справочнике «топология»? Зачем генерировать секции?

    Без самого запроса вникнуть тяжело.

    Вообще задача интересная… Можно было бы покопаться, если бы было больше исходных данных.

    Reply ↓
  74. DrZombi

    Народ, шот не пойму, все начиная от первого, Хвалят запрос. А ссылки на запрос Нет 🙁

    Дайте хоть, кто ссыль?

    Reply ↓
  75. eugeniezheludkov

    (75) нееет в «получить секции» запрос из самопального регистра а не справочника, да неважно там не сильная нагрузка идет её вообще из кода можно убрать. загружающим запросом была реализована лишь вот эта логика:

    НомерПервойСекции = Число(Сред(НачальнаяСекция,5,2));
    НомерПоследнейСекции = Число(Сред(КонечнаяСекция,5,2));
    НомерТекущейСекции = Число(Сред(Секция,5,2));
    dx = НомерТекущейСекции — НомерПервойСекции; dx = ?(dx<0,-dx,dx);
    dy = НомерПоследнейСекции — НомерТекущейСекции; dy = ?(dy<0,-dy,dy);
    Если dx>dy Тогда
    Возврат КонечнаяСекция;
    Иначе
    Возврат НачальнаяСекция;

    Показать

    вообщем просмотрел конфигурацию аж до июня 14 года , но там уже было исправлено, а еще раньше нет , только по памяти пытаться

    но смысл запроса был таков, что на вход подаются строки типа 01 и 56 и текущая позиция тоже строка к примеру 10 нужно запросом выяснить к чему 10 ближе к 01 или к 56 выдать ответ 01 .. да это тоже не важно , а важно то что в профайлере скуля этот запрос был на первом месте по заниманию ресурсов несмотря на то что он не выбирал данные, временные таблицы уничтожались

    Reply ↓
  76. ildarovich

    (77) eugeniezheludkov, задачу понял, у меня есть вариант преобразования строки в число в запросе. На взгляд затраты в нем мизерные. Никто пока не жаловался.

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

    Reply ↓
  77. ildarovich

    (76) DrZombi, запрос в начале статьи http://infostart.ru/public/90367/

    Вот он

    ВЫБРАТЬ 0 КАК Х
    ПОМЕСТИТЬ Регистр1
    ОБЪЕДИНИТЬ
    ВЫБРАТЬ 1
    ;
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ Младшие.Х + 2 * Старшие.Х КАК Х
    ПОМЕСТИТЬ Регистр2
    ИЗ Регистр1 КАК Младшие, Регистр1 КАК Старшие
    ;
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ Младшие.Х + 4 * Старшие.Х КАК Х
    ПОМЕСТИТЬ Регистр4
    ИЗ Регистр2 КАК Младшие, Регистр2 КАК Старшие
    ;
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ Младшие.Х + 16 * Старшие.Х КАК Х
    ПОМЕСТИТЬ Регистр8
    ИЗ Регистр4 КАК Младшие, Регистр4 КАК Старшие
    ;
    ////////////////////////////////////////////////////////////­///////////////////
    ВЫБРАТЬ Младшие.Х + 256 * Старшие.Х КАК Х
    ПОМЕСТИТЬ Регистр16
    ИЗ Регистр8 КАК Младшие, Регистр8 КАК Старшие
    ;
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ Младшие.Х + 65536 * Старшие.Х КАК Х
    ПОМЕСТИТЬ Регистр20
    ИЗ Регистр16 КАК Младшие, Регистр4 КАК Старшие

    Показать

    В самой статье приведены примеры применения этой таблицы. В конце статьи еще есть функция, которая строит ТЕКСТ запроса по заданному количеству чисел.

    Reply ↓
  78. ildarovich

    Для применений, связанных с генерацией дат в заданном диапазоне, удобнее применять основание 3. Тогда получается три каскада: на выходе первого — 9, второго — 81, третьего — 6551 чисел, то есть примерно 8 лет. А если взять основание 2, то три каскада будет мало — 256 чисел, на год не хватит, а четыре много — 65536, то есть примерно 80 лет.

    Для основания 3 и дат запрос будет иметь вид:

    ВЫБРАТЬ 0 КАК Х
    ПОМЕСТИТЬ Х_3
    ОБЪЕДИНИТЬ ВЫБРАТЬ 1
    ОБЪЕДИНИТЬ ВЫБРАТЬ 2
    ;
    ВЫБРАТЬ 3 * Инь.Х + Янь.Х КАК Х
    ПОМЕСТИТЬ Х_9
    ИЗ Х_3 КАК Инь, Х_3 КАК Янь
    ;
    ВЫБРАТЬ 9 * Инь.Х + Янь.Х КАК Х
    ПОМЕСТИТЬ Х_81
    ИЗ Х_9 КАК Инь, Х_9 КАК Янь
    ;
    ВЫБРАТЬ ДОБАВИТЬКДАТЕ(&Х1, ДЕНЬ, 81 * Инь.Х + Янь.Х) КАК Х
    ИЗ Х_81 КАК Инь, Х_81 КАК Янь
    ГДЕ ДОБАВИТЬКДАТЕ(&Х1, ДЕНЬ, 81 * Инь.Х + Янь.Х) <= &Х2

    Показать

    А если сразу работать с датами, то вид:

    ВЫБРАТЬ &Х1 КАК Х
    ПОМЕСТИТЬ Х2
    ОБЪЕДИНИТЬ ВЫБРАТЬ ДОБАВИТЬКДАТЕ(&Х1, ДЕНЬ, 81 * 27)
    ОБЪЕДИНИТЬ ВЫБРАТЬ ДОБАВИТЬКДАТЕ(&Х1, ДЕНЬ, 81 * 54)
    ;
    ВЫБРАТЬ ДОБАВИТЬКДАТЕ(Инь.Х, ДЕНЬ, РАЗНОСТЬДАТ(&Х1, Янь.Х, ДЕНЬ) / 3) КАК Х
    ПОМЕСТИТЬ Х4
    ИЗ Х2 КАК Инь, Х2 КАК Янь
    ;
    ВЫБРАТЬ ДОБАВИТЬКДАТЕ(Инь.Х, ДЕНЬ, РАЗНОСТЬДАТ(&Х1, Янь.Х, ДЕНЬ) / 9) КАК Х
    ПОМЕСТИТЬ Х16
    ИЗ Х4 КАК Инь, Х4 КАК Янь
    ;
    ВЫБРАТЬ ДОБАВИТЬКДАТЕ(Инь.Х, ДЕНЬ, РАЗНОСТЬДАТ(&Х1, Янь.Х, ДЕНЬ) / 81) КАК Х
    ИЗ Х16 КАК Инь, Х16 КАК Янь
    ГДЕ ДОБАВИТЬКДАТЕ(Инь.Х, ДЕНЬ, РАЗНОСТЬДАТ(&Х1, Янь.Х, ДЕНЬ) / 81) <= &Х2

    Показать

    Reply ↓
  79. skyadmin

    (17) Angeros, Не проще ли в цикле заполнить таблицу дат и передать ее в запрос?

    Reply ↓
  80. ildarovich

    (81) skyadmin, то, что вы предлагаете реально сложнее и дольше по времени. «Я этого еще не знаю и не умею» не равно «сложнее».

    Reply ↓
  81. bintape

    (80)

    Подскажите, как будет выглядеть запрос по работе с датами по основанию 4 ?

    Reply ↓
  82. ildarovich

    (84) batan,

    ВЫБРАТЬ 0 КАК Х
    ПОМЕСТИТЬ Х_4
    ОБЪЕДИНИТЬ ВЫБРАТЬ 1
    ОБЪЕДИНИТЬ ВЫБРАТЬ 2
    ОБЪЕДИНИТЬ ВЫБРАТЬ 3
    ;
    ВЫБРАТЬ 4 * Инь.Х + Янь.Х КАК Х
    ПОМЕСТИТЬ Х_16
    ИЗ Х_4 КАК Инь, Х_4 КАК Янь
    ;
    ВЫБРАТЬ 16 * Инь.Х + Янь.Х КАК Х
    ПОМЕСТИТЬ Х_256
    ИЗ Х_16 КАК Инь, Х_16 КАК Янь
    ;
    ВЫБРАТЬ ДОБАВИТЬКДАТЕ(&Х1, ДЕНЬ, 256 * Инь.Х + Янь.Х) КАК Х
    ИЗ Х_256 КАК Инь, Х_256 КАК Янь
    ГДЕ ДОБАВИТЬКДАТЕ(&Х1, ДЕНЬ, 256 * Инь.Х + Янь.Х) <= &Х2

    Показать

    Reply ↓
  83. Ibrogim

    После прочтения только один вопрос остался у меня. Как поставить автору больше одного плюса …

    Reply ↓
  84. PerlAmutor
    ВЫБРАТЬ Младшие.Х + 65536 * Старшие.Х КАК Х
    ПОМЕСТИТЬ Регистр20
    ИЗ Регистр16 КАК Младшие, Регистр4 КАК Старшие
    

    А тут вместо «Регистр4» не должно быть «Регистр16»?

    Reply ↓
  85. ildarovich

    (87) Регистр4, Регистр16 — это названия таблиц, хранящих всевозможные комбинации бит в соответствующем количестве разрядов. Регистр4 — четырехбитный регистр, в нем всего 16 разных битовых комбинаций или, что тоже самое, чисел от 0 до 15., Регистр16 — 16-ти разрядный. Комбинируя эти регистры, получаем 20-ти разрядный регистр Регистр20, в котором всего 2#k8SjZc9Dxk20 битовых комбинаций — примерно миллион.

    Если скомбинировать два 16-ти разрядных регистра, то получится 32-х разрядный регистр. Там слишком большая таблица на выходе — 3,6 миллиарда строк. Для временных таблиц это запредельные величины, вряд ли нужные на практике.

    Reply ↓
  86. trumanl

    (0) ildarovich, добрый день

    Видимо из-за изменения форматирования текста на сайте пропал знак «<» В выражении «ИЗ Аргументы ЛЕВОЕ СОЕДИНЕНИЕ Регистр10 ПО (Х * Х У)»

    Reply ↓
  87. ildarovich

    (89) Спасибо, поправил

    Reply ↓

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *