Вход | Регистрация
 
1С:Предприятие :: 1С:Предприятие 7.7 и ранее

v7: Медленно работает запрос SQLite

v7: Медленно работает запрос SQLite
Я
   Volodja
 
21.01.21 - 14:52
В чем может быть причина? Не пойму.

    тз=СоздатьОбъект("ТаблицаЗначений");
    ТаблицаЗамен.Выгрузить(тз,,,"СтароеЗначение");
    тз.НоваяКолонка("ИИН","Строка",12);
    тз.ВыбратьСтроки();
    Пока тз.ПолучитьСтроку()=1 Цикл
        _Элемент=тз.СтароеЗначение;
        тз.ИИН=_Элемент.ИИН;
    КонецЦикла;
    глБД_SQLite.УложитьТЗ(тз,"тзЗамены");
    ТекстЗапроса = "
        |SELECT
        |    Substr(тзЗамены.СтароеЗначение,7,9) as [СтарыйЭлемент :Справочник.Клиенты],
        |    СпрК.ID as [НовыйЭлемент  :Справочник.Клиенты]
        |FROM
        |    тзЗамены
        |    INNER JOIN [Справочник.Клиенты] as СпрК
        |                ON     (тзЗамены.ИИН = СпрК.ИИН) AND
        |                    (Trim(СпрК.ИИН)<>'')
        |
        |";
        
    ТекстЗапроса = "
        |SELECT
        |    Substr(тзЗамены.СтароеЗначение,7,9) as [СтарыйЭлемент :Справочник.Клиенты],
        |    СпрК.ID as [НовыйЭлемент  :Справочник.Клиенты]
        |FROM
        |    [Справочник.Клиенты] as СпрК
        |    INNER JOIN     тзЗамены
        |                ON     (тзЗамены.ИИН = СпрК.ИИН) AND
        |                    (Trim(СпрК.ИИН)<>'') AND
        |                    (СпрК.ismark <> '*')
        |
        |";


В справочнике около 100 000 записей
в тз около 200-300

Отладочная информация

Подбор индекса для таблицы SC14 :
    Ограничения: ISMARK ne; SP968[ИИН]=;
    Выбран индекс VI968: UPPER(SP968)
    Стоимость: 16
Подбор индекса для таблицы SC14 :
    Ограничения: ISMARK ne;
    Индекс не выбран.
    Стоимость: 74318
   ДенисЧ
 
1 - 21.01.21 - 14:54
AND Trim(СпрК.ИИН)<>'')

Забудь про индексы, скажи "превед" перебору таблицы
   Volodja
 
2 - 21.01.21 - 14:56
<> - Не использовать?
   ДенисЧ
 
3 - 21.01.21 - 14:56
(2) Для начала Trim() )))
Это же функция, чтобы её посчитать - нужно получить каждую строку таблицы...
   Volodja
 
4 - 21.01.21 - 14:57
Как тут тогда отсечь пустые?
   youalex
 
5 - 21.01.21 - 15:00
а в склайте разве '' <> ' '?
или у тебя там не только пробелы могут быть ?
   Volodja
 
6 - 21.01.21 - 15:02
(5) этим я игнорирую пустые ИИН
   Volodja
 
7 - 21.01.21 - 15:02
ИИН это 12-значная строка из цифр
   Volodja
 
8 - 21.01.21 - 15:04
(3) Без Trim() также долго:
(СпрК.ИИН<>'            ') AND
   Volodja
 
9 - 21.01.21 - 15:05
Индекс по ИИН есть
   youalex
 
10 - 21.01.21 - 15:10
А зачем тебе вообще это условие, 
у тебя же  INNER JOIN  тзЗамены.ИИН = СпрК.ИИН
т.е. ты можешь сначала  в ТЗ отобрать элементы без пустого ИНН?
   Volodja
 
11 - 21.01.21 - 15:15
(10) Могу, конечно. Но почему это так долго работает?
   Ёпрст
 
12 - 21.01.21 - 15:16
(11) скан всей таблички жешь
   Volodja
 
13 - 21.01.21 - 15:57
Сделал по совету (10). Отобрал предварительно все непустые ИИН.Заработало как надо.Быстро.
Получается сканирование таблицы сильно зависит от размера строки?

Это условие ведь осталось. хотя индекса нет
 СпрК.ismark <> '*'
А в этом 
(СпрК.ИИН<>'            ')
ИИН = 12 символов и тормозит уже жутко
   Sserj
 
14 - 21.01.21 - 15:59
(11) На сколько помню Djelf писал что SQLite вообще ничего не знает об индексах 1С. То что в отладке говорится "подобрн" это уже вроде как сам движок 1С сообщает. А SQLite без информации об индексах план придумывает "от балды", в частности у тебя вот решил сначала выбрать все не помеченные на удаление а потом уже связать по ИНН.
Помнится в таких случаях частенько приходилось разбивать на подзапросы, чтобы нужный индекс задействовать. Что-то типа такого:

    ТекстЗапроса = "
        |SELECT [СтарыйЭлемент :Справочник.Клиенты], [НовыйЭлемент  :Справочник.Клиенты]
        |FROM (
        |SELECT
        |    Substr(тзЗамены.СтароеЗначение,7,9) as [СтарыйЭлемент :Справочник.Клиенты],
        |    СпрК.ID as [НовыйЭлемент  :Справочник.Клиенты], 
        |    Trim(СпрК.ismark) as [ПометкаУдаления]
        |FROM
        |    [Справочник.Клиенты] as СпрК
        |    INNER JOIN     тзЗамены
        |                ON     (тзЗамены.ИИН = СпрК.ИИН) AND
        |                    (Trim(СпрК.ИИН)<>'')
        |) as T
        |WHERE NOT T.ПометкаУдаления = '*'
        |
        |";
   Volodja
 
15 - 21.01.21 - 16:09
Ок.Спасибо всем. Буду теперь аккуратнее со строками.
   Djelf
 
16 - 21.01.21 - 16:44
(14) Не совсем так. Про индексы движок то знает, но статистики индексов нет, и в случае с INNER JOIN может ошибиться в плане запроса и поменять выборку из таблиц местами.
С LEFT JOIN такой проблемы нет, выборка из таблиц местами не меняется. Все становится более предсказуемо.
Нужно смотреть план запроса через "explain QUERY PLAN "+ТекстЗапроса  и более детально через "explain QUERY PLAN "+ТекстЗапроса.

В данном запросе "ON (тзЗамены.ИИН = СпрК.ИИН) AND (Trim(СпрК.ИИН)<>'')" видимо должно быть 2 сканирования таблицы СпрК.
Первое по индексу, второе - сырым чтением, потому что Trim(СпрК.ИИН) заблокирует выборку по индексу, потому что идет вычисление перед сравнением!

А "сырое" чтение иногда оказывается быстрее, например:
SELECT count(*) FROM Справочник_Контрагенты WHERE РольПокупатель=1// по индексу будет на 10% медленнее

SELECT count(*) FROM Справочник_Контрагенты WHERE +РольПокупатель=1// а вот тут РольПокупатель модифицируется и индекс идет в ближайший лес...


Список тем форума
Рекламное место пустует  Рекламное место пустует
ВНИМАНИЕ! Если вы потеряли окно ввода сообщения, нажмите Ctrl-F5 или Ctrl-R или кнопку "Обновить" в браузере.