gifts2017

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

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

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

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

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

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

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

См. также

Подписаться Добавить вознаграждение

Комментарии

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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