Мина замедленного действия в методе 1С8 «НайтиСтроки», и … разминирование.

В этой статье рассматривается небезопасная фича метода НайтиСтроки в 1с8 и описывается способ, позволяющий сделать вызов этого метода надежным.

Немногие знают, что метод НайтиСтроки в 1С работает не всегда ожидаемым образом.

Программист предполагает, что после вызова метода строки в нем будут расположены в таком же порядке, как в исходной таблице значений. Но 1С это не гарантирует.

Поэтому рекомендую добавить в глобальный модуль две функции НайтиСтроки и ПослеНайтиСтроки и вызывать вместо  М = ТЗ.НайтиСтроки(Структура) метод М = НайтиСтроки(ТЗ, Структура). Или последовательность: М= ТЗ.НайтиСтроки(Структура);  ПослеНайтиСтроки, ТЗ);

Параметр ТЗ во второй метод передается для совместимости с 1с80, где нет функции Владелец() у строки табличной части.

 

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

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

 

 

Функция НайтиСтроки(ТЗ, Структура) Экспорт

       М = ТЗ.НайтиСтроки(Структура);

       ПослеНайтиСтроки(М, ТЗ);

КонецФункции

Процедура ПослеНайтиСтроки(М, ТЗ = Неопределено) Экспорт

       Если М.Количество() = 0 Тогда

             Возврат;

       КонецЕсли;

       //Для совместимости с 1с80

       Если ТЗ = Неопределено Тогда

             ТЗ = М[0].Владелец();

       КонецЕсли;

       ТЗ2 = Новый ТаблицаЗначений();

       ТЗ2.Колонки.Добавить(«Индекс»);

       ТЗ2.Колонки.Добавить(«Строка»);

       Для Каждого Эл ИЗ М Цикл

             НСтр = ТЗ2.Добавить();

             НСтр.Индекс = ТЗ.Индекс(Эл);

             НСтр.Строка = Эл;

       КонецЦикла;

       ТЗ2.Сортировать(«Индекс»);

       М.Очистить();

       Для Каждого Стр2 ИЗ ТЗ2 Цикл

             М.Добавить(Стр2.Строка);

       КонецЦикла;

КонецПроцедуры

 

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

 

99 Comments

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

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

    Reply
  2. fixin

    (1) никогда в отсортированной ТЗ не искал по составному ключу?

    Reply
  3. Magister

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

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

    Reply
  4. Поручик

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

    Reply
  5. echo77

    (0) Было бы неплохо получить от автора побликации пример, когда «неправильный» порядок строк в массиве, возвращаемом методом НайтиСтроки может выйти боком.

    Первое, что мне пришло на ум, это выбрать строки, а потом удалить их из таблицы. Хотя при последовательно переборе элементов массива и удалением строк из ТЗ методом Удалить(<СтрокаТаблицыЗначений>) все должно пройти корректно.

    Reply
  6. fixin

    (3) а если в небольшой? Тоже запросом, из пушки по воробьям? Господи, да откройте любую типовую, найдите поиском НайтиСтроки и посмотрите, где этот метод применяется для отсортированной таблицы.

    Вообще-то все задачи распределения, партионного списания (не только по товарам, есть задачи списания, где важна последовательность). Короче везде, где НайтиСтроки используется для отсортированной таблицы. У меня — сплошь и рядом.

    Reply
  7. Поручик

    (6) Поискал. 95% использования метода НайтиСтроки — поиск какой-то одной строки, удаление найденных строк, добавление в другую таблицу.

    Reply
  8. Famza

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

    Reply
  9. fishca

    (2) искал, но никогда не загладывался на порядок строк

    Reply
  10. KulSer

    (6) fixin.

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

    Вы можете возразить, что если в исходной таблице 10000 строк, а НайтиСтроки() возвращает 10, то два цикла по 10 строк заведомо быстрее одного цикла по 10000 строк. Но я отвечаю конкретно на пост (6), «если в небольшой». А если в «большой», то присоединяюсь к посту (3) «запрос (с использованием временных таблиц)».

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

    Reply
  11. fixin

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

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

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

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

    Reply
  12. gfvg

    Ни разу не встречал чтоб порядок строк в массиве отличался от порядка в ТЗ. Да и код предложенный автором будет вечность работать и применим(?) только для маленьких таблиц. А получать массив отсортированный как ТЗ может очень во многих случаях понадобиться, списание партий/издержек и т.д. Единственное что могу представить, почему у массива порядок строк другой получился, то это проиндексированная ТЗ.

    Reply
  13. i132

    вариант: воспользоваться опертором (ТЗ.)Скопировать(<Строки>, <Колонки>)

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

    НайдСтроки = ТЗ.НайтиСтроки(Структура);

    тз2 = ТЗ.Скопировать(НайдСтроки);

    ТЗ2.Сортировать(строкаСортировки);

    Reply
  14. fixin

    (13) а ты уверен, что он их скопирует в правильном порядке?

    это можно проверить, кстати. Если да, то это шикарный метод.

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

    Reply
  15. i132

    (14) я не пролистал синтакс-помощник до конца: можно написать еще проще:

    тз2 = ТЗ.Скопировать(СтруктураОтбора);

    ТЗ2.Сортировать(строкаСортировки)

    Циатта из синтакс-Помощника:

    Вариант синтаксиса: Скопировать по отбору

    Скопировать(<ПараметрыОтбора>, <Колонки>)

    Параметры:

    <ПараметрыОтбора> (необязательный)

    Тип: Структура.

    Ключ структуры — идентификатор колонки, а значение структуры — значение отбора.

    <Колонки> (необязательный)

    Тип: Строка.

    Список колонок для копирования в формате: «Колонка1, Колонка2…».

    —————

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

    —————

    забавный вариант удаления лишних строк из таблицы:

    ТЗ=ТЗ.Скоприровать(новый Структура(«ИмяКолонки»,ЗначениеРеквизита))

    Reply
  16. fixin

    (15) на сортировку тратится много времени. К тому же сортировка не всегда известна и равна отбору. ТЗ может быть отсортирована ХЗ как.

    Reply
  17. awk

    (0) Видел в 2007 году в БП 8 глобальную функцию Долги по фифо или как-то так, когда посмотрел на результат, там было что угодно, только не фифо. Полез — использовали именно эту функцию.

    Reply
  18. Artemuch2

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

    Reply
  19. fixin

    (17)(18) вот видите, а некоторые товарищи в начале говорили, что фигня, все через запросы… А про овраги забыли…

    Reply
  20. v.l.

    Неожиданно, я бы сказал «внезапно».

    Спасибо за статью, недавно встречал что-то подобное, но плюнул искать. Просто отсортировал ТЗ и всё.

    Reply
  21. awk

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

    Reply
  22. borman

    Статью следовало озаглавить: «На всякий случай имейте в виду…»

    Действительно ни разу не требовалась такая выборка отсортированная определенным образом.

    Reply
  23. fixin

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

    (22) ну мало ли что вас еще ждет на длинном жизненном пути…

    Reply
  24. cj512

    (17)Да даже странно, что в 1с с этим не сталкивались, при чем, что сами так кодят.

    Большинство сортировку в запросе отрабатывают.

    Reply
  25. awk

    (23) Это все равно что говорить: функция с побочным эффектом — подстава. Подстава — это недокументированное поведение.

    Например декларируем ФИФО, а реализуем рандом. У меня на поиск ошибки тогда ушло пол дня. На багфикс 1 минута.

    Reply
  26. fixin

    (24) Когда ты пишешь «большинство», прикладывай пожалуйста, ссылки на исследования, соцопросы и т.п. личный стереотип поведения, возведенный в ранг «большинство» смотрится смешно. просто совет.

    (25) все же должны быть какие-то стандарты принятые в отрасли. Еще одной подставой было преобразование в строку по региональным стандартам чисел, а не просто в 232983928392.1234. Это только в 1С так. Есть стандарты в отрасли программирования и их надо соблюдать.

    Reply
  27. Oleg_nsk

    А разве в синтаксис помощнике говорится, что функция НайтиСтроки что-то там упорядочивает? В описании сказано: «Осуществляет поиск строк таблицы значений, отвечающих заданным условиям поиска». Возвращемое значение: «Массив строк таблицы значений, соответствующих условиям поиска…» Все остальные предположения есть домыслы.

    Reply
  28. gavrikprog

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

    Нафиг изобретать велосипеды.

    Имхается, что по быстродействию будет тоже самое.

    Автор, приведи еще примеры использования…

    Reply
  29. fixin

    (27) но откуда предположить, что порядок строк при этом меняется, и не такой, как в исходной ТЗ. Однозначно — подстава.

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

    Reply
  30. amiralnar

    (29) Я даже предположить не мог, что найденные строки в массиве могут иметь какой-то порядок. Такое свойство у них отсутствует в прикладном и логическом смысле.

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

    Reply
  31. fixin

    (30) у тебя какое-то нестандартное мышление.

    Reply
  32. dkprim

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

    Reply
  33. fixin

    (32) еще возникнет, я с 1С8 с 2005 года.

    Reply
  34. adhocprog

    Спасибо! Полезная инфа.

    Reply
  35. tormozit

    Поддерживаю автора. Проблема встречалась мне неоднократно.

    Reply
  36. fixin

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

    Reply
  37. amiralnar

    (35) tormozit, Если можете, покажите, пожалуйста, в каком коде вам встречалась эта проблема? Обращались ли вы в 1С с вопросом об обсуждаемом поведении платформы?

    Reply
  38. s.sintsov

    1C вроде как никому не обещала, что метод найти строки вернет результирующий массив строк в том же порядке, что и исходные строки в таблице. Если на этом не заострили внимание в описании функции, так это только потому, что никто и подумать не мог, что профессиональные программисты будут ожидать от этой функции именно такого поведения. Вы когда-нибудь выборку по SQL таблице делали? Вы что же ожидаете, что результат выборки без дополнительного упорядочивания всегда будет в том же самом порядке, что и исходная таблица? А НайтиСтроки() — это та же самая выборка, только запрос за Вас платформа формирует.

    Reply
  39. fixin

    (38) вот потому и написана эта статья, что интуитивно ожидается что порядок строк сохранится, а на выходе он получается случайным. Причем в 80% случаев сохраняется а в 20% случайный.

    Все фичи 1с знать невозмножно, поэтому эта статья — огромный такой варнинг! 😉

    Reply
  40. Zas1402

    (13) i132, спасибо очень помогли

    Reply
  41. kapustinag

    (38), (39)

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

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

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

    Противникам таких «интуитивных ожиданий»: конечно, все люди разные, и интуиция у всех по-разному работает. Так в том-то и дело, что можно было бы легко позаботиться обо всех, предупредить их ошибки и проблемы. А можно было…сделать как сделано.

    Reply
  42. i132

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

    Работа с деревом будет быстрее если вам надо обработать всю таблицу а не только выбранные строки.

    другой вариант получения дерева из таблицы: (с использованием СКД) http://infostart.ru/public/16408/

    Reply
  43. fixin

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

    Reply
  44. fixin

    (42) повторяю в стопятьсотый раз — эта тема как раз о неинтуитивном моменте в движке 1с. Ибо интуитивно такой фигни ожидать нельзя. У всех интуиция разная, поэтому предупреждаю для тех, кто все же ожидает от 1С сохранения нормального порядка ТЗ — опасайтесь! Для этого и написана статья.

    Reply
  45. s.sintsov

    (42) Во-во, с документацией у 1С всегда были проблемы, вернее времени на это не оставалось, либо изначально была поставлена задача все тонкости работы платформы объяснять только на учебных курсах.

    Reply
  46. andy2011

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

    Reply
  47. the1
    Надеюсь, в будущих релизах 1С будет гарантировать…

    Вот это по-настоящему смешно. Сравните язык 1с8 после языка 1с77, а потом вдумайтесь — будет ли 1С что-либо делать под кодеров.

    Reply
  48. oleg974

    (1) fishca,

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

    И хм… может не в тему вопрос. А разве господина Осипова не выгоняли с сайта со скандалом и безвозвратным удалением аккаунта? 0_о

    Reply
  49. fishca

    (50)

    А разве господина Осипова не выгоняли с сайта со скандалом и безвозвратным удалением аккаунта? 0_о

    Доржи объявлял амнистию, теперь фиксин набирает обороты по новой

    Reply
  50. fixin

    (49) 1с8 по сравнению с 1с7 — шаг вперед. УФ в 1с82 — шаг вбок.

    Reply
  51. Necytij

    Долго читал тему, и все не могу понять с чего весь сырбор. ну есть проблема, и что? Я тоже никогда не сталкивался, видимо потому что работаю в основном на БП. И надеюсь, как можно меньше людей столкнутся. Но это ведь далеко не самый страшный кошмар от 1Сников. так что никакого «большого варнинга» не вижу…

    да и метод, имхо, оставляет желать лучшего.

    А почему бы не проставить индексы сначала еще В ТЗ, а потом

    ТЗ2 = ТЗ.Скопировать(ТЗ.НайтиСтроки(Структура));

    ТЗ2.Сортировать(«Индекс»);

    Это на нескольких отборах, я думаю, хорошо скажется на производительности, да и короче текст намного…

    Reply
  52. fixin

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

    Reply
  53. Necytij

    (16) (54)

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

    Вы не указали, чем такой метод по-вашему плох.

    на сортировку тратится много времени. К тому же сортировка не всегда известна и равна отбору. ТЗ может быть отсортирована ХЗ как.

    Что это вообще означает? У вас же точно такая же сортировка…

    ТЗ2.Сортировать(«Индекс»);

    М.Очистить();

    и при чем тут отбор?

    По 54 — кто отменил обращение к таблице по индексу? ТЗ[ТекущаяСтрокаТЗ2.индекс] — чем вам не ссылка на основную строку ТЗ?

    Простите, но, по-моему, вы баламут.

    Reply
  54. fixin

    (55)

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

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

    Если порядок НайтиСтроки нарушается, то возникают проблемы.

    А вы о чем, что-то я не понял?

    Reply
  55. Necytij

    1. Вы сильно преувеличиваете размер проблемы.

    2. Вот вы по ТЗ№3 определили что вам в строке Х из ТЗ№2 надо списать Нную сумму, и вы хотите в соответствующей строке ТЗ№1 убрать также Нную сумму. Ну так в строке Х ТЗ№2 есть столбец Индекс, который при обращении к таблице ТЗ№1 по индексу ласт вам ту самую строку:

    Х = ТЗ2[5]; //- нужная(в данном конкретном случае именно 6я) строка в маленькой таблице
    НужнаяСтрокаБольшойТаблицы = ТЗ[X.Индекс]; //- нужная строка в большой таблице

    Вы же свою БОЛЬШУЮ ТЗ№1 не пересортировываете по 100 раз, пока проводите списание и индексы не собьются… так?

    Reply
  56. fixin

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

    Reply
  57. Necytij

    (58)

    Вы издеваетесь!!!?????

    Сначала во всей ТЗ первоначальной проставьте в столбец индекс индекс строки перебором «для инд = 1 по …»

    Потом отбираете строки и сортируете уже новую ТЗ по столбцу индекс!!! Потом когда из строки Х в Табл.значений надо попасть в оригинальную строку вы обращаетесь к строке в ТЗ[СтрокаТаблЗначений2.Индекс].

    Сколько раз можно одно и то же писать? Занимаетесь тут маразмом. Не зря вас видать в прошлый раз забанили.

    Reply
  58. fixin

    (59) я вам объяснял, что порядок сортировки таблицы неизвестен и сортировать не есть хорошее решение. Если не верите, напишите универсальную функцию и объясните, как туда передавать порядок сортировки. Как минимум, эта универсальная функция будет сложнее моей (появится еще один параметр — порядок сортировки) и потребует от программиста больше знаний, нужно еще знать, как отсортирована исходная ТЗ.

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

    Вы хоть сто раз 2+2 = 5 напишите, от этого утверждение не станет верным. Попробуйте включить логическое мышление.

    Reply
  59. Necytij
    Процедура ПередНайтиСтроки(ТЗ)
    ТЗ.КОлонки.Добавить(«МойИндекс», НекотореОписаниеОписаниеТипаЧисло);
    для инд = 1 по ТЗ.Количество() цикл
    ТЗ[Инд].МойИндекс = инд;
    конеццикла;
    КонецПроцедуры
    
    Функция НайтиСтрокиВТЗ(ТЗ, СтруктураОтбора)
    М = ТЗ.НайтиСтроки(СтруктураОтбора);
    М.Сортировать(«МойИндекс»);
    Возврат М;
    КонецФункции
    
    Процедура Х()
    …
    ПередНайтиСтроки(ТЗ);
    …
    <некий цикл перебора в котором осуществляется последовательная выбора из ТЗ новоявленным методом НайтиСтрокиВТЗ>
    СтруктураОтбора = …;
    Строки = НайтиСтрокиВТЗ(ТЗ, СтруктураОтбора);
    для инд = 1 по Строки.Количество() цикл    //цикл всего лишь чтобы показать
    //как осуществлять обращение к основной ТЗ, вместо того чтобы городить лишнее
    Сообщить(«обращение к оригиналу строки № » + строка(инд) + » из » +
    строка(Строки.Количество()) + » выбранных: » + Строка(ТЗ[Строки[инд].МойИндекс].РеквизитТЗ));
    <конеццикла>
    инд = 0;
    для каждого Строка из Строки цикл    //цикл всего лишь чтобы показать
    //как осуществлять обращение к основной ТЗ, вместо того чтобы городить лишнее
    инд = инд +1;
    Сообщить(«обращение к оригиналу строки № » + строка(инд) + » из » +
    строка(Строки.Количество()) + » выбранных: » + Строка(ТЗ[Строка.МойИндекс].РеквизитТЗ));
    <конеццикла>
    <конеццикла>
    КонецПроцедуры

    Показать

    Проверки синтаксиса нет — писал в блокноте.

    При чем тут ваши ключи от квартиры где деньги… — беру ваш пример и убираю оттуда половину текста, оставил лишь образование столбца индекс, но не в выборке, а в основной таблице, и сортировку сразу после выборки. ЭТО ПОЧТИ И ЕСТЬ ВАШ ТЕКСТ! Только без лишнего типа такого:

    НСтр.Индекс = ТЗ.Индекс(Эл);

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

    Reply
  60. fixin

    Выражайтесь проще.

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

    Не забудьте, что у массива (именно его возращает метод НайтиСтроки) нет метода сортировки по колонке, извольте его написать, и чтобы это работало быстрее чем мой метод.

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

    Повторяю — напишите рабочую функцию в моей обработке, тогда поставим вам ЗАЧЕТ. Но как вариант принимается, правда пока не понятно, хороший ли это вариант…

    К тому же, не вижу смысла добавлять колонку индекса, если индекс каждой строки и так можно получить методом Индекс()

    Reply
  61. Necytij

    (62)

    опечатка — вместо

    М = ТЗ.НайтиСтроки(СтруктураОтбора);

    то что уже с вами обсуждали:

    М = ТЗ.Скопировать(СтруктураОтбора);

    Кодить в данном случаем нужно вам — у меня даже нет подходящего набора данных.

    Reply
  62. fixin

    (63) в структуру отбора нужно добавить еще поле созданного вами индекса

    по-прежнему не вижу преимуществ вашего метода. Напишите готовую функцию.

    Reply
  63. Necytij

    (64)

    точно?

    Если указан отбор, то только строки из отбора будут скопированы. Если отбор не указан, то будут скопированы все строки таблицы значений. Если указаны колонки, то только эти колонки будут скопированы. Иначе, будут скопированы все колонки таблицы значений.

    У кажете в отбор значение индекса, даже если пустое — максимум что вернет — 1 строку.

    Reply
  64. Necytij

    Писалось потому что настоящей работой заниматься не хотелось, писал под 8.2.14. Толстый клиент, локальная база. Данные формируются в самой форме обработки — создается таблица на 100,000 строк, в которой в несколько столбцов хранятся числа — остаток от деления на цифры. проц i3 2100. Если кто захочет посмотреть: запускаете, жмете инициализировать, ставите количество проходов, включаете замер в конфигураторе, жмете на кнопку в форме на панели основных действий. Модификация метода заключается в замене ТЗ2 при сортировке отобранных строк на список значений.

    fixin | народ | fixin модиф. (сек, замеры из отладки. Замер начинается на момент запуска процедуры с циклом выборки, заканчивается в момент окончания процедуры, инициализация и заполнение таблицы на 100к строк, сюда не входит).

    Отбор по 1/6 части строк (по 2м столбцам, где нечетное и НомерСтроки % 6 = 3, хоть второе условие и заведомо делает первое предположение верным, машина об этом не знает).

    1 проход

    0.82 vs 1.24 (при этом 0.85 сек(68%) ушло на заполнение индекса в таблицу) vs 0.64

    2 прохода

    1.64 vs 1.61 vs 1.3

    3 прохода

    2.47 vs 1.97 vs 1.95

    6 проходов

    4.92 vs 3.09 vs 3.89

    10 проходов (количество отобранных строк в сумме уже превышает количество строк таблице, некоторые строки учавтсвуют в нескольких результатах отбора)

    8.23 vs 4.65 vs 6.48

    при отборе по половине строк за 1 раз (отбор четных / нечетных строк)

    fixin | normal | fixin mod.

    1 проход

    2.49 vs 1.94 vs 1.93

    2 прохода

    4.95 vs 3.0 vs 3.83

    Reply
  65. i132

    (61) Necytij, в коде

    Функция НайтиСтрокиВТЗ(ТЗ, СтруктураОтбора)
    М = ТЗ.НайтиСтроки(СтруктураОтбора);
    М.Сортировать(«МойИндекс»);
    Возврат М;
    КонецФункции

    у вас ошибка: Найти строки возвращает массив а у массива нет метода сортировать.

    Наверно вы имели ввиду

    Функция НайтиСтрокиВТЗ(ТЗ, СтруктураОтбора,ИмяКолонкиИндекс)
    ОтобраннаяТЗ = ТЗ.Скопировать(СтруктураОтбора,ИмяКолонкиИндекс);
    ОтобраннаяТЗ.Сортировать(ИмяКолонкиИндекс);
    Возврат ОтобраннаяТЗ;
    КонецФункции

    еще можно попробовать неправильный ваиант циклической ссылки — в каждой строке хранить ссылку на саму себя, зато полсе ТЗ.Скопировать(СтруктураОтбора,ИмяКолонкиИндекс+»,»+ИмяКолонкиССылки) мы получим Таблицу из двух колонок -индекс и ссылка на начальную ТЗ

    Reply
  66. Necytij

    (67) i132,

    Если уж дошли почти до конца топика, то могли прочитать и 63, и 66. Результаты теста вашего метода.

    1 проход (по 1/6 ТЗ за выборку, с повторением предыд. результатов):

    fixin | народ | fixin модиф. | i132

    0.82 vs 1.24 vs 0.64 vs 2.09

    2 прохода

    1.64 vs 1.61 vs 1.3 vs 2.2

    3 прохода

    2.47 vs 1.97 vs 1.95 vs 2.43

    6 проходов

    4.92 vs 3.09 vs 3.89 vs 3.14

    10 проходов (количество отобранных строк в сумме уже превышает количество строк таблице, некоторые строки учавтсвуют в нескольких результатах отбора)

    8.23 vs 4.65 vs 6.48 vs 4.08

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

    Процедура ПередНайтиСтроки4(ТЗ)
    ТЗ.КОлонки.Добавить(«МойИндекс», Новый ОписаниеТипов(Новый КвалификаторыЧисла(15,0)));
    ТЗ.КОлонки.Добавить(«МояСтрока», Новый ОписаниеТипов(«СтрокаТаблицыЗначений»));
    инд = 0;
    Для каждого Строка Из ТЗ Цикл
    Строка.мойИндекс = инд;
    Строка.МояСтрока = Строка;
    инд = инд + 1;
    КонецЦикла;
    КонецПроцедуры
    
    Функция НайтиСтрокиВТЗ4(ТЗ, СтруктураОтбора)
    М = ТЗ.Скопировать(СтруктураОтбора,»МойИндекс,МояСтрока»);
    М.Сортировать(«МойИндекс»);
    Возврат М.ВыгрузитьКолонку(«МояСтрока»);
    КонецФункции
    
    Процедура ОсновныеДействияФормыМетод4(Кнопка)
    Если ТЗ.Количество() = 0 Тогда
    Возврат;
    КонецЕсли;
    
    ПередНайтиСтроки4(ТЗ);
    Для А = 1 По Проходов Цикл
    Строки = НайтиСтрокиВТЗ4(ТЗ, Новый Структура(«инд1,инд5», 1, 3));
    Сообщить(«Количество » + строка(Строки.Количество()));
    для каждого Строка из Строки цикл
    инд2 = Строка.Инд1;
    конеццикла;
    КонецЦикла;
    КонецПроцедуры

    Показать

    p.s. Жаль что тут спойлеров нет, хоть тот же код прятать.

    Reply
  67. fixin

    (68) включу ваш метод в статью.

    Только не понял, что такое методы народ и fixin_мод.

    то что fixin — это родной метод, понятно.

    Кстати, по замерам — на что больше всего тратится времени?

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

    А что, на получение строки по индексу тратится много времени, что вы для нее колонку создали?

    Reply
  68. Necytij

    Народ — потому что не этот метод был предложен не только мной.

    Модифицированный — читайте 66

    Модификация метода заключается в замене ТЗ2 при сортировке отобранных строк на список значений.

    Построчно разбирал только свой метод — народ. Корректировал методы заполнения столбца индексами. Большая часть времени? Количество проходов разное. Хотите посмотреть? Скачайте обработку из поста.

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

    Reply
  69. tulaka

    Долго сортирует

    Reply
  70. fixin

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

    Может можно обойтись без сортировки?

    смотрите, допустим мы получили методом найтистроки строки 12, 10, 45, 38, 41.

    Их правильный порядок известен как-бы, ведь есть исходная таблица.

    неужели никак нельзя расположить строки в этом порядке?

    Reply
  71. AlexO

    (72)

    только после прочтения комментов понял, о чем статья ))

    найтистроки строки 12, 10, 45, 38, 41

    В (59) Necytij об этом и писал — находите индексы своих <строки 12, 10, 45, 38, 41> в исходной таблице, и по ним ищете эти же строки в таблице-результате. Ну и сортировка по какому-либо признаку. И все при условии — в таблице-результате не делали переиндексацию после сортировки (не сбивали индекс).

    Reply
  72. ValeriVP
    Программист предполагает, что после вызова метода строки в нем будут расположены в таком же порядке, как в исходной таблице значений.

    Только не очень умный программист так будет предполагать

    Reply
  73. fixin

    (72) гладко было на бумаге. Вы забыли про время переброса из памяти на сервер и обратно.

    (75) рад за вас. я предпочитаю, чтобы неинтуитивные моменты были описаны в документации или исходя из опыта.

    Reply
  74. Magister

    (6)

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

    Был забавный случай в УПП для Украины 1.0 (которая ещё под 8.0 была).

    Там в отчете Обороты счета (или Анализ счета, запамятовал уже) данные по счетам в колонки выводились с использованием что-то типа:

    СоответствиеСчетов = Новый Соответствие;
    … заполнение …
    Для Каждого Счет Из СоответствиеСчетов Цикл
    …
    КонецЦикла

    Так вот, в 8.0 Соответствие обходилось всегда в том же порядке, в котором в него добавлялись элементы. В 8.1 это поведение изменилось, и порядок обхода стал другим (в документации, кстати, и в 8.0 было написано, что порядок обхода не определен).

    Естественно, отчет при переходе на 8.1 выводил белиберду.

    Мне этот момент хорошо запомнился 🙂



    Ещё неплохой момент с библиотекой glibc в Linux.

    В документации сказано, что memcpy предназначена только для копирования непересекающихся областей памяти. Поведение в случае пересекающихся неопределено. Что, впрочем, непомешало криворуким программистам Adobe использовать именно эту функцию в Flash Player (вместо memmove, которая как раз отработает правильно всегда).

    С очередным обновлением glibc звук в Flash Player стал хрипеть, а именно — потому, что в glibc оптимизировали функцию memcpy, и её поведение изменилось (всё также в пределах документации).



    К чему это я. Криворукие программисты есть не только в 1С 🙂

    Reply
  75. fixin

    (77) статья и признана объяснить одну неочевидную вещь.

    Reply
  76. daho

    fixin — давай в том же духе!!! надо ж кому-то этот навоз ворошить… :))) а вообще спасибо, такие фичи знать всегда полезно… вот только хрен их все блин запомнишь….

    а программисты бывают не только криворукие, но и пьяные, обкуренные, уставшие, кормящие детей, играющие попутно в квейк и шахматы ну и в конец просто зае%$#ннные чем или кем либо… 🙂

    а талант не пропьешь!!!

    Reply
  77. MPV

    Спасибо за информацию. Недавно задумывался как раз над этим вопросом, но лень искать было.

    Reply
  78. i132

    Еще пример борьбы с неочевидной сортировкой — сортировка по кнопке сортировать — например если сортировать таблицу по колонке с Значением = const порядок строк поменяется (не надо было сортирровать!)

    Вот как можно улучшить кнопку сортировать: http://infostart.ru/public/125020/

    Reply
  79. i132

    Про РезультатЗапроса.Выгрузить() в документации тоже не сказано про порядок строк, когда нибудь может перемешать

    Reply
  80. fixin

    (82) гм, действительно… придется пересортировывать для надежности.

    Reply
  81. Buster

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

    При правильном расположении рук возвращается всё в том же порядке, а не в каком-то хаотичном.

    Следует не лепить костыли куда попало, а научится писать правильные алгоритмы.

    Reply
  82. fixin

    (84) ну да, ну да… 😉

    Reply
  83. Yury1001

    На днях состряпал отчет с динамическим количеством колонок, использовал СабжМетод с расчетом на правильный (однозначный) порядок результата поиска, т.к. работа бюджетная – заморачиваться не стал, пока всё в порядке. Если для последних релизов (на сегодня 8.2.15) статься справедлива могут перемешаться цифры внутри строк, если что воспользуюсь (13) (15).

    Reply
  84. fixin

    (86) рад, что пригодилось.

    Reply
  85. fzt

    Улыбнули страсти.

    А вот спасибо Автор. Пиши ещё =)

    Только что собирался использовать сей метод, решил отгуглить для копипаста, буду иметь ввиду.

    Интуитивно ожидал сохранения порядка строк.

    Кстати по поводу интуиции. Я это ожидал поскольку много лет работал с кодом, который получает весомый пакет данных. И только апосля упорно с ним работает, сортирует, раскладывает на классификаторы etc. Дело привычки обжувать данные в памяти, нежели тратить ресурсы на запросы к БД. Да и специфика такова, что в момент запроса, БД может физически испариться, я не говорю про возможные блокировки, ожидание в очереди.

    То есть алгоритмы поиска придуманные для Я.В.У. почти все гарантируют сохранение порядка строк. Всё-таки непривычно, что 1С по каждому чиху запрос пользует.

    P.S. Использовать не буду, но в мемориз покладу.

    P.P.S. Товарищи защищавшие писателей справки 1С, ваша въедливость при чтении документации заставляет думать о большом количестве свободного времени. Заведите себе девушку, жену, любовницу или ещё какую личную жизнь. Это когда радуешься НЕ работе ;-). Столько просьб привести примеры из жизни на 1С. Господа, систем под которые пишутся скрипты или бинарный код великое множество. Весьма разнообразные области человеческой деятельности автоматизируются. Если кто-то вынужден въедливо читать документацию на родном мне языке, обдумывая запятые — значит это с системой что-то не так.

    Reply
  86. termit@mail.ru

    Автор, респект. Подтверждаю: дотачивал обработку «Групповая обработка документов и справочников» в бухгалтерии для госучреждений (скорее всего аналогичное поведение и в стандартной бухгалтерии 2.0) на платформе 8.2

    Столкнулся с тем, что после попытки повторно обработать документы они обрабатывались в неправильной последовательности. Массив для обработки там как раз отбирается этой функцией по полю «Пометка» исходной таблицы с отобранными для обработки документами. Стал копать — наткнулся на эту тему.

    Так что:

    1) люди(в т.ч. программисты 1с, т.к. это их обработка) всё-таки ожидают от этого метода правильный порядок строк

    2) тема полезна, автору плюс

    Reply
  87. tango

    -: не просто «не тратить время», а вредная статья, курочащая мозги.

    впрочем, проголосувавшим — барабан навстречу

    Reply
  88. fixin

    (90) и в чем же ее вред? в том что показывает неявный глюк 1с?

    (89) 1с — не для людей. Даже в документации не предупреждает об этом.

    Reply
  89. AleksR

    Статья полезная.

    Добавьте только в функцию НайтиСтроки() строку:

    Возврат М;

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

    Reply
  90. sergb1979

    При перепродажах использую аналогичное.

    Чтобы номера строк не менялись.

    Reply
  91. Morales

    (68) Necytij, Спасибо, кратко и понятно, буду использовать

    Reply
  92. AlexO

    (84) Buster,

    При правильном расположении рук возвращается всё в том же порядке, а не в каком-то хаотичном.

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

    Либо вы открыли недокументированную фишку, которую разработчики БД упустили из виду (сама получилась), либо ничего не поняли из проблемы несинхронности порядка записей при их Создании-Записи-Чтении.

    Т.е. проигнорировали саму эту проблему абсолоютно )

    Reply
  93. AlexO
    Если вы предложите более быстрый способ упорядочивания массива найденных строк, буду благодарен.

    (69)

    включу ваш метод в статью

    И где? ))

    И предложили, и благодарность он заслужил, а ты, Сергей, даже обещание не сдержал 🙂

    Reply
  94. AlexO

    (93) sergb1979,

    Чтобы номера строк не менялись.

    Каким образом у вас меняются «номера строк», если «номера строк» присваиваются при создании объекта (в данном случае это ТЗ)?

    Т.е. как бы вы не тасовали записи, номера строк всегда будут по-порядку и от 1 до n-1 :))

    А если имели ввиду «порядок строк», то к номерам строк это отношение не имеет. Точнее, порядок и определяет номера, но не наоборот.

    Следовательно, либо вы:

    — не писали некий механизм «При перепродажах использую аналогичное»

    — не разобрались, как этот механизм «При перепродажах» работает (и обратили внимание совсем не на суть механизма, а на следствие — номера строк)

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

    Reply
  95. fixin

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

    Reply
  96. AlexO

    (98) тем не менее, именно в комментариях писали и продолжают писать (уже после множества «тема уже достаточно раскрыта») о том, что либо «проблема не существует», либо «да тут все просто, я сто раз уже так делал».

    Reply
  97. fixin

    (99) а вы как считаете? 😉

    Reply
  98. fzt

    (3) Magister, мне похожее понадобилос прямо сейчас, но я порядок не предпологаю. Контролирую.

    В запросах тоже порядок не гарантируется, тут уж как индекс на диск положен. ТЗ скармливаю запросу как временную таблицу, мне нужно получить некоторые данные, а совать на вход в запрос все данные из ТЗ — ресурсоёмко, много их. Глупо не оптимально потом построчно проводить поиск между результатом запроса и ТЗ. Менее ресурсоёмко в один проход записать результаты.

    Редко, но нужно.

    (5) echo77, собственно выше и смежный пример. Есть некая ТЗ, помимо прочих столбцов (с данными) незаполнены артикулы номенклатуры, нужно получить их из справочника. Позиций номенклатуры в ТЗ на порядки меньше количества её в справочнике. Естественно это будет запрос, вот только построчный поиск соответствий — путь низкой квалификации, или раздолбайства (когда время выполнения выходит за разумные пределы).

    Reply
  99. VL_admin

    (1) fishca, расскажу как у меня эта проблема возникла.

    Данные в ТЗ забираю из базы данных oracle. Если кто не знает, то 1С до Оракла по возможностям языка очень далеко. В 1С нет ни case в order by, ни аналитических функций, ни прочих фишек. Поэтому грех не воспользоваться возможностями для сортировки, чтобы потом в 1С не пересортировывать дикими способами.

    Так вот после того как отсортированная Ораклом ТЗ попала в 1С я делаю выборку из нее с помощью НайтиСтроки().

    И мне нужно сохранить порядок, а его нет….

    Для себя решил поставить перебор таблицы вместо НайтиСтроки().

    Reply

Leave a Comment

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