Быстрая индексированная выборка элементов справочника по коду

27.09.13

Разработка - Механизмы платформы 1С

Столкнулся с такой проблемой - при поиске запросом ссылок на список элементов справочника по кодам операция происходит крайне медленно. Разбор статистики по индексам показал что поиск по коду индексы не использует, а при большом количестве записей в справочнике ( порядка нескольких миллионов) это становится проблемой.

Столкнулся с такой проблемой - при поиске запросом ссылок на список элементов справочника по кодам операция происходит крайне медленно. Разбор статистики по индексам показал что поиск по коду индексы не использует, а при большом количестве записей в справочнике ( порядка нескольких миллионов) это становится проблемой.

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

проблема решилась таким образом:

1) Создается индекс в субд типа 

CREATE INDEX ids_ap_index_by_code
  ON _reference2
  USING btree
  (_code);

2) Выборка осуществляется запросом с использованием конструкции

ГДЕ  НекийСправочник.Код В(&СписокКодовХ)

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

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

 

В результате выло получено ускорение выборки с 11 сек. до 0,15 сек.

 

Была написана такая функция:

 

 

 

 

Функция БыстраяИндексированнаяВыборкаЭлементовСправочникаПоКоду(ВидСправочника,Запрос,МассивКодов,ИспользоватьВременныеТаблицы,ЛимитКодовНаОдинЗапрос=300,СтруктураДопреквизитов=неопределено)
     // Функция расчитана на использование самодельного индекса по одной  колонке "код" справочника.
     // Предполагается что: коды в справочнике уникальны
     //                     МассивКодов желательно передавать без дублей
     //                     На выходе ожидается список уникальных значений
     //                     Индекс создан вручную в субд запросом типа : CREATE INDEX ids_ap_index_by_code ON _reference2  USING btree (_code);
     // На входе получает:
     //                   Имя вида справочника,
     //                   объект Запрос,
     //                   массив кодов для поиска,
     //                   Указание использовать в запросе вывод во временную таблицу ( объекту запрос должен быть назначен менеджер временных таблиц) или нет.
     //                   ЛимитКодовНаОдинЗапрос для условия код в (массивкодов_х), по умолчанию не более 300 штук, при слишком большом значении индексированный поиск может не сработать
     //                   Структуру доп реквизитов, где ключ - псевдоним колонки, значение- текст для выборки данных вида  НекийСправочник.ВидПоступленияТовара
     //                                                        или более сложный вариант к примеру:  case when НекийСправочник.ВидПоступленияТовара = Значение(Перечисление.ВидыПоступленияТоваров.Комиссия) then НекийСправочник.Поставщик else null end  
     // На выходе дает:
     //                Если ИспользоватьВременныеТаблицы=ложь то таблицу значений   [код,колонкидопреквизитов_если_запрашивались,Ссылка]
     //                если ИспользоватьВременныеТаблицы=истина булево Результат запроса Пустой() ,
     //                        а в менеджере временных таблиц создается временная таблица  ВидСправочника_БИВПК  [код,колонкидопреквизитов_если_запрашивались,Ссылка], Индексированная по коду
     //------------------------------------------// GtG // 26.09.2013 10:31:54
     ДопРеквизиты="";

     Если СтруктураДопреквизитов=Неопределено ТОгда
     Иначе
         // пришел массив с текстовкой допреквизитов
         Для каждого стр из СтруктураДопреквизитов цикл
             ДопРеквизиты=ДопРеквизиты+стр.Значение+" как "+Стр.Ключ+","+Символы.ПС;
         КонецЦикла;
    КонецЕсли;    
    
    
    
    
     ЗапросТекст="ВЫБРАТЬ
                  |    НекийСправочник.Код КАК Код,"+ДопРеквизиты+"
                  |    НекийСправочник.Ссылка
                  |ИЗ
                  |    Справочник."+ВидСправочника+" КАК НекийСправочник
                  |ГДЕ
                  |    НекийСправочник.Код В(&СписокКодовХ)";
      
      Х=0;  
      СписокКодов=Новый Массив;
      МассивСписковКодов=Новый Массив;
      Для Каждого Стр Из МассивКодов Цикл
          Х=Х+1;
          СписокКодов.Добавить(Стр);
          Если Х%ЛимитКодовНаОдинЗапрос=0 Тогда
              МассивСписковКодов.Добавить(СписокКодов);
              СписокКодов=Новый Массив;
          КонецЕсли;  
      КонецЦикла;    
      Если СписокКодов.Количество()<>0 Тогда
          МассивСписковКодов.Добавить(СписокКодов);
      КонецЕсли;
      
      Х=0;
      
      Запрос.Текст="";
      ДЛя Каждого СписокКодовПоиска Из МассивСписковКодов Цикл
          Х=Х+1;
          
          Запрос.Текст=Запрос.Текст+Символы.ПС;
          Запрос.Текст=Запрос.Текст+СтрЗаменить(ЗапросТекст,"&СписокКодовХ","&СписокКодов"+Формат(Х,"ЧГ="));
          Запрос.Текст=Запрос.Текст+Символы.ПС;
          Запрос.Текст=Запрос.Текст+?(Х=МассивСписковКодов.Количество(),"","Union All");
          
          Запрос.УстановитьПараметр("СписокКодов"+Формат(Х,"ЧГ="),СписокКодовПоиска);
      КонецЦикла;      
      
      Если ИспользоватьВременныеТаблицы=Истина ТОгда
          ИмяВременнойТаблицы=" Into "+ВидСправочника+"_БИВПК";
          СортировкаИндексирование=" INDEX ";
      Иначе
          ИмяВременнойТаблицы="";
          СортировкаИндексирование=" ORDER ";
      КонецЕсли;  
      
      
      ДопРеквизиты="";
      
      Если СтруктураДопреквизитов=Неопределено ТОгда
      Иначе
          // пришла структура с текстовкой допреквизитов
          Для каждого стр из СтруктураДопреквизитов цикл
              ДопРеквизиты=ДопРеквизиты+Стр.Ключ+" как "+Стр.Ключ+","+Символы.ПС;
          КонецЦикла;
      КонецЕсли;
      
      
      
      Запрос.Текст="Select distinct Base.Код,"+ДопРеквизиты+" Base.Ссылка "+ ИмяВременнойТаблицы+" From ("+Символы.ПС+
                      Запрос.Текст+ Символы.ПС+
                    " ) as Base "+СортировкаИндексирование+" by Base.Код ";
            
    Если ИспользоватьВременныеТаблицы=Истина ТОгда
        Запрос.Выполнить();        
    Иначе
        Возврат Запрос.Выполнить().Выгрузить();
    КонецЕсли;    
КонецФункции    

быстрый поиск большие объемы данных функция

См. также

Механизмы платформы 1С Работа с интерфейсом Программист Стажер Платформа 1С v8.3 Бесплатно (free)

Про ООП в 1С и о том, как сделать свой код более кратким и выразительным при помощи использования текучего интерфейса (fluent interface).

03.02.2025    5999    bayselonarrend    126    

59

Механизмы платформы 1С Программист Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.

14.01.2025    7786    dsdred    57    

99

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    11506    bayselonarrend    21    

162

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    7849    dsdred    18    

82

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Бесплатно (free)

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

24.01.2024    27006    YA_418728146    33    

73
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. AlX0id 28.09.13 13:05 Сейчас в теме
мм.. А если добавить реквизит, аналогичный коду с указанием индексации - не прокатит?
Сам не пробовал на таких объемах - просто спрашиваю )
7. Evilgrym 194 30.09.13 16:46 Сейчас в теме
(1) AlX0id,
Не прокактит. 1С-ка создает индекс, типа

CREATE UNIQUE INDEX _reference2_byfield2510_rr
ON _reference2
USING btree
(_fld2508rref, _idrref);

Т.е. в этом индексе 2 колонки - интересующее нас поле и ссылка на элемент справочника.
Но в запросе мы используем условие всего лишь по одному полю из двух. В результате Postgre SQL считает этот индекс неподходящим и лезет перебором по всей таблице.

Да, и так, для статистики - в справочнике без малого 14 млн записей. Записи постоянно добавляются и используется по большей части последняя, самая свежая, треть. Поэтому самодельный индекс сделан убывающим, чтоб свежие данные были в более быстром доступе. 1С-ка так не умеет.
2. Armando 1402 28.09.13 16:02 Сейчас в теме
Меня вот это смущает:
Соединение таблицы справочника и временной таблицы с кодами не привело к использованию индекса
3. vvr908 450 29.09.13 13:29 Сейчас в теме
А какая была СУБД?
ShantinTD; +1 Ответить
6. Evilgrym 194 30.09.13 16:43 Сейчас в теме
4. Famza 85 30.09.13 09:37 Сейчас в теме
(0)
Соединение таблицы справочника и временной таблицы с кодами не привело к использованию индекса.

А какой был первоначальный запрос? Ладно бы для 7.7 проблема субд и запросов, а для 8.2...
5. Evilgrym 194 30.09.13 16:42 Сейчас в теме
(4) Famza,

Первоначальный вариант был такой:
//------------------------------------------
Выбрать
тз.код
Поместить СписокКодов
из &tz как ТЗ
Индексировать по Код
;

Выбрать
Спр.код,
Спр.ссылка
из
Справочник.какойтотам как Спр
ВНУТРЕННЕЕ СОЕДИНЕНИЕ СписокКодов как СписокКодов
по Спр.код=СписокКодов.код
//---------------------------------------------
8. tango 546 30.09.13 16:54 Сейчас в теме
новосозданный индекс потом какой жизнью живет?
1с его не знает.
БД обновляет?
если нет - то это как бы разовая фича, время на ее создание надо учитывать
если да - то шаманство в пофигураторе может дать такой же эффект?
9. Evilgrym 194 30.09.13 17:08 Сейчас в теме
(8) tango,

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

Нюанс может возникнуть при создании новой базы и при изменении в структуре данных. Индекс может пропасть, но это дело поправимое.

Создавать индекс можно и не выгоняя всех из базы, используя команду CREATE INDEX CONCURRENTLY. Думает подольше конечно.
10. Evilgrym 194 30.09.13 17:36 Сейчас в теме
И вообще, по наблюдениям, все индексы, которые создает 1С-ка содержат в себе как минимум 2 поля, индексируемое и _idrref, а это приводит к тому что в реальной жизни, полной извращенных ситуаций, субд отказывается их использовать.

Например в справочнике на 82 колонки имеется 65 индексов созданных конфигуратором, но выборки в основном делаются с помощью построителя запросов с отбором по нескольким колонкам и из 65 индексов хоть как-то используется только 18. Остальные вообще бесполезны. Ну ладно там в таблице всего 80 тысяч записей... Место-то жрется...
11. tango 546 30.09.13 17:42 Сейчас в теме
(10)
вернее дает команду субд их создать

мы ведь тоже тольк дали команду...
почему индекс через пофигуратор содержит второе поле?
может быть, это не совсем те индексы, которые БД создает по нашему криту?
16. aspirator23 340 02.10.13 07:01 Сейчас в теме
(10)Evilgrym, 82 колонки имеется 65 индексов - имеет смысл?
С одной стороны запрос столько индексов не может использовать. С другой стороны получаем задержки при записях из-за расходов на записи индексов.
12. tango 546 30.09.13 17:43 Сейчас в теме
стремно как-то в типовых убивать индексы от разрабов
14. Evilgrym 194 30.09.13 17:48 Сейчас в теме
(12) tango,
Ну я и не агитирую за их убийство.
Просто, когда база под 150 гиг, как-то мысли всякие начинают в голову приходить, где б такое сэкономить да подускорить...
15. tango 546 30.09.13 17:49 Сейчас в теме
(14) я тут бегло глянул на ЗУП - "убивать", конечно, не комильфо. скажем так: "убрать"
13. tango 546 30.09.13 17:47 Сейчас в теме
вообще, любопытная картинка:
ЗУП, СотрудникиОрганизаций
ДатаДоговора - индекс
ДатаПриемаНаРаботу - не индекс

приколисты там, у флагмана, сидят
17. rus128 2 02.10.13 10:17 Сейчас в теме
"Задача усложнялась теще"
а тёща тут при чем? :-)
18. madkat 02.10.13 13:04 Сейчас в теме
У Вячеслава Гилева есть хороший инструмент, по анализу индексов. Вот я ему предлагал написать подсистему к любой стандарной конфе, в которой можно было указать для какого объекта и по каким полям проверять наличие инексов, и в случает отсутствия их создавать.
Оставьте свое сообщение