bdd2

Процедуры группировки объекта "ТаблицаЗначений"

Опубликовал Олег Валуйский (waol) в раздел Программирование - Практика программирования

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

Заинтересовал объект ИндексированнаяТаблица, решил сравнить ее метод Группировать() с тем, что использую для группировки родной 1с "ТаблицаЗначений".
Экспериментировал на таблице с 5 колонками, порядка 4000 строк.
Выигрыш 1с++ где то в 3-10 раз, в зависимости от варианта группирования.
Большие таблицы, свыше 60000 строк моя процедура уже виснет, в то время как Группировать() довольно быстро справляется с таблицами свыше 200000 (дальше уже не проверял)

Разработку в то же время оставляю, поскольку не все пользуются ВК.
Добавлю также процедуру, для группировки таблиц с "вложенными периодами", что может быть полезно для получения кросс-отчетов, что не умеет делать Индексированная таблица при помощи встроенных методов. Применима для таблиц, у которых присутствует одна колонка тип "ТаблицаЗначений" со структурой типа "ДатаПериода, Сумма", "ДатаПериода, План,Факт" и т.п. (вариант структуры передается в параметрах процедуры). В таблице значений на выходе на каждом уровне группировки также имеет эту колонку с соответствующим образом рассчитанной таблицей.
Для этой процедуры уже требуется использование объекта ИндексированнаяТаблица, но таблица, передаваемая в качества параметра, должна быть типа "ТаблицаЗначений"

Скачать файлы

Наименование Файл Версия Размер
gr
.1205758205 17,03Kb
31.12.14
125
.1205758205 17,03Kb 125 Скачать

См. также

Добавить вознаграждение
Комментарии
1. Артур Аюханов (artbear) 840 17.03.08 16:52 Сейчас в теме
Приведи свой код группировки по Индексированной таблице.
ИМХО наверняка ты что-то неверно написал :(
Основная беда ИТЗ - сильный расход памяти при группировке.
2. Олег Валуйский (waol) 219 17.03.08 17:02 Сейчас в теме
там все предельно просто

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

табИТ.Группировать("Контрагент:Контрагент; Док:Док","Сумма",1);

3. Олег Валуйский (waol) 219 17.03.08 17:03 Сейчас в теме
помимо этого я написал процедуру, аналогичную СоздатьГруппировкиВТаблице именно для индексированной таблицы. Но там совсем медленно все протекает.
4. Евгений Мартыненков (JohnyDeath) 291 17.03.08 17:53 Сейчас в теме
а ты попробуй:
Код
табИТ.Группировать("Контрагент:*Контрагент; Док:Док","Сумма",1);
Показать полностью

приятно удивишься!
5. Евгений Мартыненков (JohnyDeath) 291 17.03.08 17:55 Сейчас в теме
Желательно везде ставить "*", т.е. делай так:
Код
табИТ.Группировать("Контрагент:*Контрагент; Док:*Док","Сумма",1);
Показать полностью

и ещё. вот это не совсем понял:
Судя по всему, из за того, что в Индексированной Таблице не удаляются колонки при свертке.
если ты нехочешь, чтоб оставались "дети", то и ставь третий параметр в методе "группировать" = 0
6. Олег Валуйский (waol) 219 17.03.08 19:17 Сейчас в теме
(5). Да, звездочка действительно рулит )). Спасибо за просвещение
если писать
табИТ.Группировать("Контрагент:*Контрагент; Док:*Док","Сумма",1);
то скорость метода Группировать возрастает, на глаз, этак в 3-4 раза.

а третий параметр, как я понял из описания, касается только последнего уровня:

"чРасшифровкаПоследнегоУровня - число, если 1, то в каждой строке последнего уровня группировки будет таблица с расшифровкой, содержащая строки исходной таблицы в нетронутом виде.".

собственно, так он и работает
7. Евгений Мартыненков (JohnyDeath) 291 17.03.08 19:37 Сейчас в теме
Ну расскажи теперь про замеры.
И кстати, надеюсь, ты ставишь старт счетчика до "табИТ.Группировать("Контрагент:*Контрагент; Док:*Док","Сумма",1);", и не до "ЗначениеИзФайла(ИмяФайла,таб);" ? ;)
8. Олег Валуйский (waol) 219 17.03.08 23:47 Сейчас в теме
(7) я похож на дауна ?? ))

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

Кстати, Евгений, в документации про нее не сказано,
ты не мог бы просвятить, где бы можно было получить более подробное описание класса (я пользовался описанием, скачанным с 1cpp.ru)?

9. Алексей Лапицкий (Lapitskiy) 807 18.03.08 04:56 Сейчас в теме
Актуальность не потеряна. Для тех случаев, когда невозможно использовать ВК.
10. Евгений Мартыненков (JohnyDeath) 291 18.03.08 10:51 Сейчас в теме
(8) в документации написано:
Синтаксис: Группировать(стрГруппировки, стрКолонкиСумм, [чРасшифровкаПоследнегоУровня = 0])
Параметры:
стрГруппировки - тип: Строка. Строка, описывающая требуемую структуру группировки. Задаётся в виде <ИмяИндекса1>: <ИндексноеВыражение1> [; <ИмяИндекса2>: <ИндексноеВыражение2> ... ]. ИндексноеВыражение - строка в том же формате, что и для метода ДобавитьИндекс()

теперь смотрим на метод "ДобавитьИндекс":

Синтаксис: ДобавитьИндекс(стрИдентификатор, стрВыражение, [чТолькоУникальныеЗначения = 0])
Параметры:
стрИдентификатор - тип: Строка. Идентификатор создаваемого индекса;
стрВыражение - тип: Строка. Индексное выражение. Индексное выражение состоит из списка идентификаторов колонок, разделённого запятыми. Если перед именем колонки стоит символ '-', то сортировка осуществляется в обратном порядке. Если перед именем колонки стоит символ '*', то сортировка осуществляется по внутреннему представлению объекта....

т.е. получается так: если ты не ставишь звёздочку, то идёт ещё одно обращение к БД, за счет чего и начинаются не нужные нам тормоза ;)
11. Евгений Мартыненков (JohnyDeath) 291 18.03.08 10:51 Сейчас в теме
(9) Lapitskiy, а когда невозможно использовать ВК?
12. Олег Валуйский (waol) 219 18.03.08 12:01 Сейчас в теме
JohnyDeath - твоя правда, моя невнимательность
13. Олег Валуйский (waol) 219 18.03.08 12:06 Сейчас в теме
Lapitskiy если невозможно использовать ВК, то актуальность этих измерений вообще нулевая.

На больших таблицах (порядка 100000) проверил - 1с на этой процедуре уходит в глубокую задумчивость, из которой вывести удалось через диспетчер задач. Ну может быть, машина у меня слабая. 1с++ довольно резво расправлялась с таблицей свыше 200000 строк, создавая в ней упомянутые две группировки + последняя
14. Евгений Мартыненков (JohnyDeath) 291 18.03.08 12:30 Сейчас в теме
(13) я считаю, что ТЗ размером в 200000 строк - это слишком. Ведь ты же берёшь их откуда-то? Наверное из БД запросом. Может на этапе запроса выкидывать(группировать,сворачивать) нужные строки? Вряд ли кому-то понадобится отчет, у которого будет столько строк.
15. Олег Валуйский (waol) 219 18.03.08 13:29 Сейчас в теме
я пока только начинаю экспериментировать с прямыми запросами, причем работаю в ДБФ (через СоздатьОбъект("OLEDBData")). И пока не смог добиться, чтобы в запросе работала группировка ((.
Посему и стал искать быстрые способы группировки, чтобы не терялся выигрыш в скорости прямого запроса. Первые мои шаги общения с компонентой, поэтому не судите строго
16. Артур Аюханов (artbear) 840 19.03.08 10:16 Сейчас в теме
Прошу автора поправить свое описание про "Выигрыш моей процедуры" :)
Ты же убедился, что ИТЗ группирует шустрее ? :)
17. Олег Валуйский (waol) 219 19.03.08 12:28 Сейчас в теме
18. Олег Валуйский (waol) 219 19.03.08 13:21 Сейчас в теме
artbear
хотя, если уж совсем быть строгим, то сортировка по внутреннему представлению может дать проигрыш уже при выводе результатов
19. Евгений Мартыненков (JohnyDeath) 291 19.03.08 13:53 Сейчас в теме
20. Олег Валуйский (waol) 219 19.03.08 14:09 Сейчас в теме
(19) ты про сортировку ? согласись, кому интересно видеть отчет с сортировкой по внутреннему представлению
21. Евгений Мартыненков (JohnyDeath) 291 19.03.08 14:47 Сейчас в теме
(20) Обычно интересует сортировка по показателям (сумма, приход, расход и т.д.). Тогда немного непонятна твоя фраза "может дать проигрыш уже при выводе результатов".. Кому дать проигрыш? По сравнению с кем/чем?
22. Алексей (ADirks) 176 19.03.08 15:05 Сейчас в теме
(21) Вообще-то waol рассуждает вполне здраво. Для вывода сгруппированой ИТ нужно будет по новой создавать индексы, но уже не по внутреннему представлению, а по строковому. К примеру
ИТ.Группировать("Товар: *Товар", "Сумма");
ИТ.УдалитьИндекс("Товар");
ИТ.ДобавитьИндекс("Товар", "Товар");
вот на последней то строчке мы и проваливаемся. И такую операцию надо будет проделывать со всеми потомками.
23. Артур Аюханов (artbear) 840 19.03.08 15:30 Сейчас в теме
Даже без использования * ИТЗ выигрывает на средних и больших таблицах, на маленьких, естественно, будет выигрыш обычных видов группировок.
(22) Лех, а ты не думал как-то оптимизировать именно этап создания таблиц-потомков, может быть, написать свой распределитель памяти или еще что?
24. Артур Аюханов (artbear) 840 19.03.08 15:33 Сейчас в теме
(waol) А с другой стороны, опытные пацаны делают так:
1) как выше написано, группируют уже в запросе
2) если не получается п.1, значит, они уже в запросе получают доп. поля типа КонтрагентНаименование/КонтрагентКод и т.д. для исключения лишних обращений к базе данных, и далее группировка делается уже не по Контрагент без *, а по КонтрагентНаименование/КонтрагентКод
25. Олег Валуйский (waol) 219 19.03.08 15:58 Сейчас в теме
(24) что касается п.1 - давай предположим, что он не получается

а что касается п.2 - то группировать по наименованию - не очень корректно, поскольку наименования не всегда уникальны, т.получается группировка Код и еще группировка Наименование, опять таки при условии, что уникален код, т.е. лишняя группировка. В общем - нюансы, и для моего опыта не все так однозначно.
26. Артур Аюханов (artbear) 840 19.03.08 16:06 Сейчас в теме
(25) Ну так тебе никто не мешает использовать еще одно ОГРОМНОЕ преимущество ИТЗ - группировку по нескольким полям, например, Группировать("Группировка1:КонтрагентНаименование,КонтрагентКод;Группировка2 и т.д.") !
Ты пойми, я призываю тебя к тому, чтобы исключить/минимизировать лишние обращения к базе данных!
27. Артур Аюханов (artbear) 840 19.03.08 16:08 Сейчас в теме
ИТЗ умеет не только индексировать и группировать по нескольким полям таблицы.
Такую фишку через штатный код 1С с более-менее подходящим быстродействием универсальным способом так просто не сделаешь :)
А тут халява :)
28. Евгений Мартыненков (JohnyDeath) 291 19.03.08 16:14 Сейчас в теме
(22) Ну это ты написал для сортировки по "наименованию". Тут - да, будет польза, а я писал про сортировку по показателям.

(25. п.2)
А ты делай индекс, состоящий из двух колонок: Наименование и Код (предполагая, что эта комбинация уникальна).
29. Евгений Мартыненков (JohnyDeath) 291 19.03.08 16:15 Сейчас в теме
млин, по п.2 Артур уже опередил...
30. Артур Аюханов (artbear) 840 19.03.08 16:18 Сейчас в теме
(waol) Нужно расшифровывать про минимизацию обращений к базе через запросы? Или нет?
31. Олег Валуйский (waol) 219 19.03.08 16:27 Сейчас в теме
(30) не получилось у меня использовать метод группировки в запросах с использованием
OLEDBData ((... я уже писал, кажется.
Если дашь полезный совет - не откажусь ))

про группировку по нескольким полям - спасибо за намек, я пока ее не исследовал, только собирался посмотреть, есть ли такая возможность )). Приколно - я в сабжевой процедурине все собираюсь сделать такую возможность, да все руки не доходят. Возможно теперь уже и не дойдут.
32. Алексей (ADirks) 176 20.03.08 08:15 Сейчас в теме
(23) Про возможности сокращения накладных расходов конечно думал, хотя не слишком упорно :)
Правильнее было бы вообще не создавать вложенных таблиц, а создавать некую деревянную структуру для обхода, и отдельно висящие итоговые строки, и каким-то образом организовать обход всего этого добра.
33. Артур Аюханов (artbear) 840 20.03.08 10:05 Сейчас в теме
(31) 1. Весь смысл в том, чтобы ты все необходимые поля доставал в запросе - например, для Контрагентов нужны сам элемент, его наименование, код, в запросе соответственно нужно получить ИД, Наименование, Код.
Для ИТЗ неважно, каким образом получен запрос - прямой запрос 1С++ или обычный запрос 1С.
Главное, чтобы ИТЗ брал из таблицы готовые данные, а не пытался обратиться к базе данных.

Т.е. вместо довольно медленного ИТЗ.Группировать("Контрагент:Контрагент", "Сумма") нужно юзать что-то вроде ИТЗ.Группировать("Контрагент:КонтрагентНаименование,КонтрагентКод", "Сумма")
.
2. Максимально оптимально, чтобы и группировка была в запросе, но раз у тебя это пока не получается, можешь делать группировку в ИТЗ, скорости у ИТЗ не столь плохие при соблюдении условия из п.1
34. Олег Валуйский (waol) 219 20.03.08 10:50 Сейчас в теме
artbear в принципе все логично, исходя из предыдущего диалога ))

довольно полезные советы, благодарствую

ADirks это уже будет по-видимому другой объект
за ИндексированнаяТаблица отдельное спасибо, это действительно прорыв!
сравнимо с появлением обычной ТаблицаЗначений в 77

35. Олег Валуйский (waol) 219 21.03.09 10:51 Сейчас в теме
в процедурах СоздатьГруппировкиВТаблице, СоздатьГруппировкиВТаблицеСВложеннымиПериодами исправлена ошибка. Возникала в тех случаях, когда группировка возникала в последней строке таблицы
36. Андрей Konishevskyi (hlud) 06.11.09 22:33 Сейчас в теме
а вобще можно и так :
ИТЗ.Группировать("Контрагент:КонтрагентНаименование,*Контрагент",
"Сумма")
:)
37. Олег Валуйский (waol) 219 06.11.09 23:21 Сейчас в теме
(36) верно ) за промежуток между 35 и 36 сообщением я не поверишь, это уже понял ) и то что штука наимощнешая в общем тоже