Оптимизация конфигураций на платформе 1C SQL
На главную
Обратная связь
Карта сайта
Оптимизация конфигураций на платформе 1C SQL
ГлавнаяМатериалыСтатьиРазработка
  • Деятельность

  • Материалы

  •      › Скачать
         › Статьи
         › FAQ
         › Новости
  • Контакты

  • Форум



  • e-mail:
    icq: 169296011
    © 2003-2010 Шемякин Павел





    Разработка

    Опубликована: 11.06.2009, отредактирована: 11.06.2009 Автор: Шемякин Павел

    Быстрый поиск средствами библиотеки ToySQL

    В ходе работы над конфигурацией заказчика столкнулись с проблемой медленного поиска в больших справочниках. Число элементов в справочниках в данный момент зашкаливает за 300 тысяч. Поиск стандартными средствами по первым буквам занимает до 10 секунд. Поиск подстроки вообще очень долго. В общем-то типовая задача для тех, кто занимается разработкой на 7-ке в SQL. И в общем-то эта задача уже решалась не раз - с помощью 1С++ или с помощью других средств. В каком-то смысле это изобретение велосипеда. В основном заметка полезна пользователям библиотеки ToySQL (хотя и на 1С++ это легко переносится). Особенность работы процедуры - поиск по подстроке в реквизитах наименование, код, а также в реквизитах с сортировкой. Есть возможность поиска по агрегатным реквизитам (поиск через точку). Результаты поиска отображаются в форме списка с помощью установки фильтра по найденным элментам, тем самым можно произвести выбор из этого списка без дополнительных выкрутасов. Встроить в модуль формы списка достаточно просто - добавляем на форму кнопку поиска с вызовом:

    глБыстрыйПоиск(Контекст,Синонимы,,ДопРеквизиты)

    Текст основной и вспомогательных процедур:

    Функция ПолучитьСиноним(Синоним,Синонимы)
        Если Синонимы = 0 Тогда
            Возврат Синоним;
        Иначе
            Стр = Синонимы.Получить(Синоним);
            Если ПустаяСтрока(Стр) = 1 Тогда
                Возврат Синоним;
            Иначе
                Возврат Стр;
            КонецЕсли;
        КонецЕсли;
    КонецФункции

    Функция ИсключитьИзСписка(Рекв,Список)
        Если Список = 0 Тогда
            Возврат 0;
        Иначе
            Если Список.НайтиЗначение(Рекв) > 0 Тогда
                Возврат 1;
            КонецЕсли;
        КонецЕсли;
        Возврат 0;
    КонецФункции

    Процедура глБыстрыйПоиск(Конт,Синонимы=0,Исключить=0,ДопРеквизиты=0) Экспорт
        РеквизитыПоиска = СоздатьОбъект("СписокЗначений");
        Вид = Конт.Вид();
        Мета = Метаданные.Справочник(Вид);
        Если Мета.ДлинаНаименования > 0 Тогда
            Если ИсключитьИзСписка("Наименование",Исключить) = 0 Тогда
                РеквизитыПоиска.ДобавитьЗначение("Наименование",ПолучитьСиноним("Наименование",Синонимы));
            КонецЕсли;
        КонецЕсли;
        Если (Мета.ДлинаКода > 0) И (Мета.ТипКода = "Текстовый") Тогда
            Если ИсключитьИзСписка("Код",Исключить) = 0 Тогда
                РеквизитыПоиска.ДобавитьЗначение("Код",ПолучитьСиноним("Код",Синонимы));
            КонецЕсли;
        КонецЕсли;
       
        Для н=1 По Мета.Реквизит() Цикл
            Рекв = Мета.Реквизит(н);
            Если Рекв.Сортировка = 1 Тогда
                Если Рекв.Тип = "Строка" Тогда
                    Если ИсключитьИзСписка(Рекв.Идентификатор,Исключить) = 0 Тогда
                        РеквизитыПоиска.ДобавитьЗначение(Рекв.Идентификатор,?(ПустоеЗначение(Рекв.Синоним)=1,Рекв.Идентификатор,Рекв.Синоним));
                    КонецЕсли;
                КонецЕсли;
            КонецЕсли;
        КонецЦикла;
       
        Если ПустоеЗначение(ДопРеквизиты) = 0 Тогда
            Стр = "";
            Для н=1 По ДопРеквизиты.РазмерСписка() Цикл
                Зн = ДопРеквизиты.ПолучитьЗначение(н,Стр);
                РеквизитыПоиска.ДобавитьЗначение(Зн,Стр);
            КонецЦикла;
        КонецЕсли;
       
        Зн = "";
        Если РеквизитыПоиска.ВыбратьЗначение(Зн,,,,1) = 1 Тогда
            Стр = "";
            Если ВвестиСтроку(Стр,"Введите строку поиска",50) = 1 Тогда
                п = Найти(Зн,".");
                Если п > 0 Тогда
                    Рекв = Лев(Зн,п-1);
                    МетаРекв = Мета.Реквизит(Рекв);
                    Поиск = Рекв+"."+Сред(Зн,п+1);
                   
                    ТекстЗапроса = "SEL ECT [Спр.Ссылка]
                    |FR OM [Справочник."+Вид+"] Спр WITH (NOLOCK)
                    |JOIN ["+МетаРекв.Тип+"."+МетаРекв.Вид+"] "+Рекв+" WITH (NOLOCK) ON [Спр."+Рекв+"] = ["+Рекв+".Ссылка]
                    |WHERE UPPER(["+Поиск+"]) LIKE '%"+Врег(Стр)+"%'
                    |ORDER BY [Спр.Наименование]";
                   
                Иначе
                    ТекстЗапроса = "SEL ECT [Ссылка] FR OM [Справочник."+Вид+"] WITH (NOLOCK) WHERE UPPER(["+Зн+"]) LIKE '%"+Врег(Стр)+"%'
                    |ORDER BY [Наименование]";
                КонецЕсли;
               
                Запрос = СоздатьОбъект("ToyQuery");
                Запрос.Вернуть1С = 1;
                Если Запрос.МетаЗапрос(ТекстЗапроса) = 1 Тогда
                    ТЗ = СоздатьОбъект("СписокЗначений");
                    Запрос.Выгрузить(ТЗ);
                    Если ТЗ.РазмерСписка() > 0 Тогда
                        Конт.ИспользоватьСписокЭлементов(ТЗ);
                    Иначе
                        Сообщить("Ничего не найдено");
                        Конт.ИспользоватьСписокЭлементов();
                    КонецЕсли;
                Иначе
                    Сообщить(Запрос.Ошибка);
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
    КонецПроцедуры

     наверх