Имя: Пароль:
1C
1C 7.7
v7: Медленно работает запрос SQLite
0 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(СпрК.ИИН)<>'')

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

Это условие ведь осталось. хотя индекса нет
СпрК.ismark <> '*'
А в этом
(СпрК.ИИН<>'            ')
ИИН = 12 символов и тормозит уже жутко
14 Sserj
 
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.ПометкаУдаления = '*'
        |
        |";
15 Volodja
 
21.01.21
16:09
Ок.Спасибо всем. Буду теперь аккуратнее со строками.
16 Djelf
 
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 // а вот тут РольПокупатель модифицируется и индекс идет в ближайший лес...