Имя: Пароль:
 
1C
1C 7.7
v7: 1с++ ускорение Запрос.УложитьСписокОбъектов
0 dk
 
21.01.19
12:12
исходные:
1с++, SQL 2000 / 2008
Проблема:
Довольно долго укладываются большие списке объектов (1000 элементов и больше)

Без иерархии: 2430 мс
С иерархией: 2394 мс
ВыполнитьSQL_ИзТЗ: 229 мс

Ниже замеры и код
1 dk
 
21.01.19
12:13

Процедура Сформировать()

    Запрос = СоздатьОбъект("ODBCRecordSet");
    
    ТекстЗапроса = "SELECT TOP 3000 ID [Счет $Справочник.Счета] FROM $Справочник.Счета (NOLOCK)";
    
    ВремТЗ = СоздатьОбъект("ТаблицаЗначений");
    
    Запрос.ВыполнитьИнструкцию(ТекстЗапроса, ВремТЗ);
    
    СЗ_Фильтр = СоздатьОбъект("СписокЗначений");
    ВремТЗ.Выгрузить(СЗ_Фильтр,,,"Счет");
    
    //СЗ_Фильтр.ВыбратьЗначение(1);
    
    Сообщить("**************************************");
    
    Нач = _GetPerformanceCounter();
    Запрос.УложитьСписокОбъектов(СЗ_Фильтр, "#Фильтр1");
    Сообщить("Без иерархии: " + (_GetPerformanceCounter() - Нач));
    Сообщить("Кол-во: " + Запрос.ВыполнитьСкалярный("SELECT COUNT(*) FROM #Фильтр1"));
    
    Нач = _GetPerformanceCounter();
    Запрос.УложитьСписокОбъектов(СЗ_Фильтр, "#Фильтр2", "Счета");
    Сообщить("С иерархией: " + (_GetPerformanceCounter() - Нач));
    Сообщить("Кол-во: " + Запрос.ВыполнитьСкалярный("SELECT COUNT(*) FROM #Фильтр2"));
    
    Нач = _GetPerformanceCounter();
    ТекстЗапроса = "
    |IF OBJECT_ID(N'tempdb..#Фильтр3','U') IS NOT NULL DROP TABLE #Фильтр3
    |;
    |CREATE TABLE #Фильтр3 (Счет Char(9), UNIQUE CLUSTERED (Счет))";
        
    Запрос.ВыполнитьИнструкцию(ТекстЗапроса);    
    
    Запрос.Подготовить("INSERT INTO #Фильтр3 VALUES(?)");
    Запрос.ВыполнитьSQL_ИзТЗ(ВремТЗ);
    Сообщить("ВыполнитьSQL_ИзТЗ: " + (_GetPerformanceCounter() - Нач));
    Сообщить("Кол-во: " + Запрос.ВыполнитьСкалярный("SELECT COUNT(*) FROM #Фильтр3"));
    
КонецПроцедуры
2 dk
 
21.01.19
12:16
Собственно вопрос
кто-то занимался ускорением уложитьсписок объектов?
либо есть универсальный запрос по получению иерархии шустрый?
3 trad
 
21.01.19
12:19
а если так?
CREATE TABLE #Фильтр3 (Счет Char(9), PRIMARY KEY CLUSTERED (Счет))
4 dk
 
21.01.19
12:23
(3) пофигу
**************************************
Без иерархии: 2370
Кол-во: 3000
С иерархией: 2590
Кол-во: 3000
ВыполнитьSQL_ИзТЗ: 221
Кол-во: 30
5 dk
 
21.01.19
12:23
Кол-во: 3000
6 trad
 
21.01.19
12:25
затестил у себя (на $Справочник.Номенклатура):

**************************************
Без иерархии: 890
Кол-во: 3000
С иерархией: 1062
Кол-во: 3286
ВыполнитьSQL_ИзТЗ: 127
Кол-во: 3000
7 dk
 
21.01.19
12:26
ну гдето в 7-8 раз шустрее
8 Туц
 
21.01.19
12:27
Альтернатива это импорт из командной строки.
9 Mikeware
 
21.01.19
12:36
а нужен ли такой список? может, его сразу формировать во временной таблице запросом?
10 Туц
 
21.01.19
12:36
Кстати через adodb можно бинарник пихнуть ввиде xml
11 dk
 
21.01.19
12:38
(9) ну это например может быть какой-то охрененный список товаров из Excel загружен в несколько тыс строк или группа первого уровня
12 Туц
 
21.01.19
12:45
Ещё вариант. Укладывать не таблицу и список строк. Т.е. строку таблицы приводить суммировать в строку. Чисто в теории будет кратный количеству колонок выйгрышь
13 Mikeware
 
21.01.19
12:48
(11) так по идее по адо можно сразу из экселя...
а группу первого уровня можно запросом собрать
14 trad
 
21.01.19
12:48
имхо, проблема в медленном итерировании списка внутрях УложитьСписокОбъектов
15 Sserj
 
21.01.19
12:48
(11) Если список товаров то ничего не сделаешь. А если группа первого уровня, да и вообще любая группа лучше сделать через CTE фильтр групп и условие по родителю.
16 trad
 
21.01.19
12:50
вердикт. сделать свой УложитьСписок на основе ВыполнитьSQL_ИзТЗ.
Разворот иерархии написать самому или спиимствовать у УложитьСписок
17 dk
 
21.01.19
12:53
(15) sql 2000 не дружит с cte
(16) угу, смотрю профайлером как штатный робит и как выполнитьтз
18 Вафель
 
21.01.19
12:55
а зачем нежен фильтр из 3000 элементов?
19 Sserj
 
21.01.19
12:56
(17) Ну там в топике 2008 было написано. Ради CTE да оконных функций можно было бы и поднапрячься с переходом на посвежее :)
20 dk
 
21.01.19
12:59
(18) см (11)
21 Mikeware
 
21.01.19
13:06
(16) другими словами, не использовать универсальный способ, на написать частный для частных случаев.
22 trad
 
21.01.19
13:08
(21) честно сказать, я удивлен, что неиерархический УложитьСписокОбъектов так проигрывает ВыполнитьSQL_ИзТЗ
23 Mikeware
 
21.01.19
13:15
(22) из-за универсальности. но да, проигрыш слишком велик...
24 trad
 
21.01.19
13:33
так дело в том, что УложитьСписок не имеет какой-то там универсальности.
То, что он умеет еще делать запрос по развороту иерархии, не влияет на само "укладывание"
То, что в таблице есть еще служебное поле "isfolder", тоже не сказывается
25 Salimbek
 
21.01.19
15:46
(24) Может кто допилит на использование Массив, Структура, Соответствие или чего еще быстрого (мечтательно) :-)
26 ADirks
 
22.01.19
08:50
(25) Нет смысла, т.к. накладные расходы на уровне СУБД на порядок (порядки?) больше, чем на исполнение кода 1С.

Самостоятельная реализация УложитьСписок() в данном случае полезна в исследовательских целях, а то действительно непонятно, откуда такие тайминги.
27 Дык ё
 
22.01.19
09:12
(16) какое чудесное слово - "спиимствовать" :)

а включение режимrpc на тайминги уложитьсписок не влияет?
28 trad
 
22.01.19
14:24
(27) режимrpc на уложитьсписок не влияет
29 dk
 
25.01.19
12:37
с прямым заполнением в скуле пока не прокатило
-------------
сделал просто если в темп
потом из темпа забираем тока группы
эти группы штатно укладываем
склеиваем оба списка
-------------
Процедура Сформировать4()

    Запрос = СоздатьОбъект("ODBCRecordSet");
    
    ВремТЗ = СоздатьОбъект("ТаблицаЗначений");
    ВремТЗ.НоваяКолонка("Товар", "Справочник.Номенклатура");
    
    //ВремТЗ.НоваяСтрока();
    //ВремТЗ.Товар = ВыбНоменклатура;
    
    ТекстЗапроса = "SELECT TOP 1000 ID [Товар $Справочник.Номенклатура] FROM $Справочник.Номенклатура (NOLOCK) WHERE Id = :ВыбТовар--WHERE ISFOLDER = 2";
    Запрос.УстановитьТекстовыйПараметр("ВыбТовар", ВыбНоменклатура);
    
    Запрос.ВыполнитьИнструкцию(ТекстЗапроса, ВремТЗ);
    
    СЗ_Фильтр = СоздатьОбъект("СписокЗначений");
    ВремТЗ.Выгрузить(СЗ_Фильтр,,,"Товар");
    
    Сообщить("**************************************");
    
    Нач = _GetPerformanceCounter();
    Запрос.УложитьСписокОбъектов(СЗ_Фильтр, "#Фильтр1");
    Сообщить("Без иерархии: " + (_GetPerformanceCounter() - Нач));
    Сообщить("Кол-во: " + Запрос.ВыполнитьСкалярный("SELECT COUNT(*) FROM #Фильтр1"));
    
    Нач = _GetPerformanceCounter();
    Запрос.УложитьСписокОбъектов(СЗ_Фильтр, "#Фильтр2", "Номенклатура");
    Сообщить("С иерархией: " + (_GetPerformanceCounter() - Нач));
    Сообщить("Кол-во: " + Запрос.ВыполнитьСкалярный("SELECT COUNT(*) FROM #Фильтр2"));    
    
    Нач = _GetPerformanceCounter();
    ТекстЗапроса = "
    |IF OBJECT_ID(N'tempdb..#Фильтр3','U') IS NOT NULL DROP TABLE #Фильтр3
    |;
    |CREATE TABLE #Фильтр3 (Товар Char(9), UNIQUE CLUSTERED (Товар))
    |;
    |IF OBJECT_ID(N'tempdb..#Фильтр4','U') IS NOT NULL DROP TABLE #Фильтр4
    |;
    |CREATE TABLE #Фильтр4 (Товар Char(9), UNIQUE CLUSTERED (Товар))
    |;
    |IF OBJECT_ID(N'tempdb..#Фильтр6','U') IS NOT NULL DROP TABLE #Фильтр6
    |;
    |CREATE TABLE #Фильтр6 (Товар Char(9), UNIQUE CLUSTERED (Товар))";
        
    Запрос.ВыполнитьИнструкцию(ТекстЗапроса);    
    
    Запрос.Подготовить("INSERT INTO #Фильтр3 VALUES(?)");
    Запрос.ВыполнитьSQL_ИзТЗ(ВремТЗ);
    //Сообщить("ВыполнитьSQL_ИзТЗ: " + (_GetPerformanceCounter() - Нач));
    //Сообщить("Кол-во ВыполнитьSQL_ИзТЗ: " + Запрос.ВыполнитьСкалярный("SELECT COUNT(*) FROM #Фильтр3"));
    
    ТекстЗапроса = "
    |    INSERT INTO #Фильтр4
    |    SELECT Ном.ID Товар
    |    FROM $Справочник.Номенклатура AS Ном With (NOLOCK)
    |        INNER JOIN #Фильтр3 Ф0 (NOLOCK) ON (Ф0.Товар = Ном.ID) AND (Ном.ISFOLDER = 1)
    |";
    
    Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
    //Сообщить("Фильтр4: " + (_GetPerformanceCounter() - Нач));
    //Сообщить("Кол-во Фильтр4: " + Запрос.ВыполнитьСкалярный("SELECT COUNT(*) FROM #Фильтр4"));
    
    ТекстЗапроса = "
    |    SELECT Ф0.Товар [Товар $Справочник.Номенклатура]
    |    FROM #Фильтр4 Ф0 (NOLOCK)
    |";
    
    Врем2 = СоздатьОбъект("ТаблицаЗначений");
    Запрос.ВыполнитьИнструкцию(ТекстЗапроса, Врем2);
    //Сообщить("Фильтр4_1: " + (_GetPerformanceCounter() - Нач));
    //Сообщить("Кол-во Фильтр4_1: " + Врем2.КоличествоСтрок());
    
    СЗ_Фильтр = СоздатьОбъект("СписокЗначений");
    Врем2.Выгрузить(СЗ_Фильтр,,,"Товар");
    
    Запрос.УложитьСписокОбъектов(СЗ_Фильтр, "#Фильтр5", "Номенклатура");
    //Сообщить("Фильтр5: " + (_GetPerformanceCounter() - Нач));
    //Сообщить("Кол-во Фильтр5: " + Запрос.ВыполнитьСкалярный("SELECT COUNT(*) FROM #Фильтр5"));    
    
    ТекстЗапроса = "
    |    INSERT INTO #Фильтр6
    |    SELECT Ф3.Товар FROM #Фильтр3 Ф3 (NOLOCK)
    |    LEFT JOIN #Фильтр4 Ф4 (NOLOCK) ON Ф3.Товар = Ф4.Товар
    |    WHERE Ф4.Товар IS NULL
    |
    |    UNION-- ALL
    |    
    |    SELECT Val FROM #Фильтр5 (NOLOCK)
    |    
    |";
    
    Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
    
    ТекстЗапроса = "
    |IF OBJECT_ID(N'tempdb..#Фильтр3','U') IS NOT NULL DROP TABLE #Фильтр3
    |;
    |;
    |IF OBJECT_ID(N'tempdb..#Фильтр4','U') IS NOT NULL DROP TABLE #Фильтр4
    |;";
        
    Запрос.ВыполнитьИнструкцию(ТекстЗапроса);    
    
    Сообщить("Фильтр6: " + (_GetPerformanceCounter() - Нач));
    Сообщить("Кол-во Фильтр6: " + Запрос.ВыполнитьСкалярный("SELECT COUNT(*) FROM #Фильтр6"));    

    
КонецПроцедуры
30 dk
 
25.01.19
12:38
замеры
**************************************
Без иерархии: 797
Кол-во: 1000
С иерархией: 957
Кол-во: 1000
Фильтр6: 240
Кол-во Фильтр6: 1000
**************************************
Без иерархии: 810
Кол-во: 1000
С иерархией: 921
Кол-во: 1000
Фильтр6: 216
Кол-во Фильтр6: 1000
**************************************
Без иерархии: 832
Кол-во: 1000
С иерархией: 920
Кол-во: 1000
Фильтр6: 222
Кол-во Фильтр6: 1000
**************************************
Без иерархии: 764
Кол-во: 1000
С иерархией: 1502
Кол-во: 34142
Фильтр6: 1036
Кол-во Фильтр6: 34142
**************************************
Без иерархии: 701
Кол-во: 1000
С иерархией: 1538
Кол-во: 34142
Фильтр6: 972
Кол-во Фильтр6: 34142
**************************************
Без иерархии: 9
Кол-во: 1
С иерархией: 117
Кол-во: 7289
Фильтр6: 165
Кол-во Фильтр6: 7289
**************************************
Без иерархии: 9
Кол-во: 1
С иерархией: 120
Кол-во: 7289
Фильтр6: 170
Кол-во Фильтр6: 7289
**************************************
Без иерархии: 9
Кол-во: 1
С иерархией: 118
Кол-во: 7289
Фильтр6: 183
Кол-во Фильтр6: 7289
**************************************
Без иерархии: 54
Кол-во: 1
С иерархией: 214
Кол-во: 7289
Фильтр6: 194
Кол-во Фильтр6: 7289
**************************************
Без иерархии: 10
Кол-во: 1
С иерархией: 36
Кол-во: 58
Фильтр6: 61
Кол-во Фильтр6: 58
**************************************
Без иерархии: 10
Кол-во: 1
С иерархией: 51
Кол-во: 58
Фильтр6: 81
Кол-во Фильтр6: 58
**************************************
Без иерархии: 11
Кол-во: 1
С иерархией: 37
Кол-во: 58
Фильтр6: 61
Кол-во Фильтр6: 58
**************************************
Без иерархии: 12
Кол-во: 1
С иерархией: 43
Кол-во: 58
Фильтр6: 67
Кол-во Фильтр6: 58
31 dk
 
25.01.19
12:42
если в фильтре тока группы, то проигрывает чутка если в абсолюте смотреть
а на смешанных списках выигрывает от 40% до 800%
32 dk
 
25.01.19
12:43
может найдутся энтузиасты которые в скуле реализуют уложитьсписокобъектов
33 trad
 
25.01.19
13:32
//*******************************************
Процедура УложитьСписокОбъектов(пСЗ, пИмяТаблицы, пВидСправочника = "")
    
    ТЗ = СоздатьОбъект("ТаблицаЗначений");
    пСЗ.Выгрузить(ТЗ);
    
    рс = СоздатьОбъект("ODBCRecordset");
    рс.ВыполнитьИнструкцию("
    |if exists(select * from tempdb..sysobjects where id = object_id('tempdb.." + пИмяТаблицы + "'))
    |  drop table " + пИмяТаблицы + "
    |create table " + пИмяТаблицы + " (val char(9) collate database_default, isfolder tinyint, primary key clustered (val))
    |");
    
    рс.Подготовить("insert into " + пИмяТаблицы + " values (?, 2)");
    рс.ДобПараметр(1, 14, 9, 0);
    рс.ВыполнитьSQL_ИзТЗ(ТЗ);
    рс.Закрыть();
    
    Если ПустаяСтрока(пВидСправочника) = 0 Тогда
        рс.ВыполнитьИнструкцию("
        |set nocount on
        |
        |update " + пИмяТаблицы + "
        |set
        |    isfolder = 1
        |from " + пИмяТаблицы + " tab
        |inner join $Справочник." + пВидСправочника + " as ref (nolock) on ref.id = tab.val
        |where
        |    ref.isfolder = 1
        |
        |declare @folders table(val char(9) collate database_default, primary key clustered (val))
        |while 1=1 begin
        |
        |    insert into @folders
        |    select
        |        val
        |    from " + пИмяТаблицы + " tab
        |    where tab.isfolder = 1
        |
        |    if @@rowcount = 0
        |        break
        |    
        |    insert into " + пИмяТаблицы + "
        |    select
        |        id,
        |        isfolder
        |    from $Справочник." + пВидСправочника + " (nolock)
        |    where
        |        parentid in (select val from @folders) and
        |        id not in (select val from " + пИмяТаблицы + ")
        |    
        |    delete " + пИмяТаблицы + "
        |    where
        |        val in (select val from @folders)
        |    
        |end
        |delete @folders
        |
        |set nocount off
        |");
    КонецЕсли;
    
КонецПроцедуры
34 trad
 
25.01.19
13:33
(32) что значит "в скуле реализуют" ?
35 trad
 
25.01.19
13:36
(33)
**************************************
Без иерархии: 770
Кол-во: 3000
Без иерархии2: 115
Кол-во: 3000
С иерархией: 836
Кол-во: 3286
С иерархией2: 201
Кол-во: 3286
ВыполнитьSQL_ИзТЗ: 116
Кол-во: 3000
36 trad
 
25.01.19
13:37
(33) - это реализация моего предложения в (16)
37 dk
 
25.01.19
13:59
(33) спасибо - самый шустрый вариант
AdBlock убивает бесплатный контент. 1Сергей