Подводный камень предсказуемости поведения разных версий 1sqlite.многобукафокНу, например, надо посчитать количество коробок по реализациям в развозке (документ ходка).
Запрос №1
SELECT
р.IDDOC [Реализация :Документ.Реализация],
sum(р.Количество*р.Коэффициент/е.Коэффициент) as Коробки
FROM
ДокументСтроки_Реализация as р
INNER JOIN (SELECT
х.Накладная
FROM ДокументСтроки_Ходка as х
WHERE х.IDDOC=' 11WRO ') as s
ON s.Накладная = р.IDDOC
LEFT JOIN Справочник_Номенклатура as н ON р.Номенклатура = н.ID
LEFT JOIN Справочник_Единицы as е ON е.ID = н.ОсновнаяЕдиница
GROUP BY р.IDDOC
Оптимизатор может сначала выбрать ходки, а потом реализации (что хотелось бы), а может все сделать наоборот.
1sqlite/sqlite - время
1.0.2.3/3.6.33 - 3мс
1.0.2.4/3.7.0 - 24000мс
1.0.2.6/3.7.10 - 24000мс
1.0.2.6/3.7.11 - 24000мс
1.0.2.6/3.7.17 - 3мс
1.0.2.6/3.8.11.b - 24000мс
1.0.2.6/3.8.11.1.bf0 - 3мc
И это несмотря на то, что стоимость у Ходок 36, а у Реализаций 40
Заменим в 2х строках LEFT JOIN на INNER JOIN, дадим оптимизатору порезвится!
INNER JOIN Справочник_Номенклатура as н ON р.Номенклатура = н.ID
INNER JOIN Справочник_Единицы as е ON е.ID = н.ОсновнаяЕдиница
1sqlite/sqlite - время
1.0.2.3/3.6.33 - 3мс
1.0.2.4/3.7.0 - 45000мс
1.0.2.6/3.7.10 - 15000мс
1.0.2.6/3.7.11 - 16000мс
1.0.2.6/3.7.17 - 3мс
1.0.2.6/3.8.11.b - 647мс
1.0.2.6/3.8.11.1.bf0 - 550мc
Все стало еще непредсказуемее. А все потому, что в дело вступили еще два ограничения и оптимизатор может сначала пройти по номенклатуре потом по ходке, потом по реализации (1.0.2.6/3.8.11.b) или по номенклатуре, реализации и ходке (1.0.2.4/3.7.0)
Кстати если сделать фильтр по номенклатуре, то в этом запросе 1.0.2.6/3.8.11.1.bf0 победит всех в легкую!.
Заменим RIGHT JOIN на IN, это должно выправить мозги оптимизатору.
SELECT
р.IDDOC [Реализация :Документ.Реализация],
sum(р.Количество*р.Коэффициент/е.Коэффициент) as Коробки
FROM
ДокументСтроки_Реализация as р
LEFT JOIN Справочник_Номенклатура as н ON р.Номенклатура = н.ID
LEFT JOIN Справочник_Единицы as е ON е.ID = н.ОсновнаяЕдиница
WHERE р.IDDOC IN
(SELECT
х.Накладная val
FROM ДокументСтроки_Ходка as х
WHERE х.IDDOC=' 11WRO ')
GROUP BY р.IDDOC
1sqlite/sqlite - время
1.0.2.3/3.6.33 - 1500мс
1.0.2.4/3.7.0 - 1500мс
1.0.2.6/3.7.10 - 1500мс
1.0.2.6/3.7.11 - 1500мс
1.0.2.6/3.7.17 - 3мс вычеркнут из за багов по IN
1.0.2.6/3.8.11.b - 3мс
1.0.2.6/3.8.11.1.bf0 - 3мc
Более предсказуемое поведение. Заметно, что до 3.7.17 нет оптимизации по IN.
Вот такая вот проблема в предсказуемости поведения запросов разных версий 1sqlite.Чтения без индекса нет ни в одном из этих запросов, все эти запросы, во всех вариантах попадают в индекс, вот только перфразирую слегка: "Все говорят что смысл есть в индексе, но не многие знают в каком"
Победительем вышел 1.0.2.6/3.7.17, показавший во всех вариантах 3мс. Был снят с призового места, т.к. был уличен в багах по оптимизаии IN.
Уговорить 1.0.2.4/3.7.0-1.0.2.6/3.7.11 на 3мс не удалось (не совсем это правда, это сделать можно, добавив группировку по номенклатуре и засунув всю эту конструкцию как вложенный запрос, но это не красиво!).
Новый победитель 1.0.2.6/3.8.11.1.bf0
3.8.11 можно уговорить и через cte, но это не 3мс, а 5мс, что тоже не так плохо!
WITH cte(Реализация, Номенклатура, Коробки) AS (
SELECT
х.Накладная,0,0
FROM ДокументСтроки_Ходка as х
WHERE х.IDDOC=' 11WRO '
UNION
SELECT
р.IDDOC as IDDOC,
р.Номенклатура,
sum(р.Количество*р.Коэффициент/е.Коэффициент) as Коробки
FROM
ДокументСтроки_Реализация as р
INNER JOIN cte on cte.Реализация=р.IDDOC
LEFT JOIN Справочник_Номенклатура as н ON р.Номенклатура = н.ID
LEFT JOIN Справочник_Единицы as е ON е.ID = н.ОсновнаяЕдиница
)
SELECT
cte.Реализация [Реализация $Документ.Реализация],
cte.Коробки
FROM cte
WHERE cte.Номенклатура<>0
С 1.0.2.6/3.8.11.b надо сильно подумать!
Возможно нужно задействовать новое в 3.8.х, не заполняющееся поле (количество строк таблицы) при ответе выбора индекса.
Или (вариант максимум) сделать аналог analyse и хранить это в базе sqlite, но разумеется уже не в :memory: базе.
P.S. да, это дебильный запрос, с "умными" запросами дело обстоит несколько легче.