Используя SQL-запрос, SQLite сканирует всю таблицу и загружает все значения во временное дерево b-tree для их упорядочения, делая любой индекс бесполезным. Это будет очень медленно и использовать много памяти на больших таблицах:
explain query plan select * from 'table' order by abs(10 - value) limit 1;
0|0|0|SCAN TABLE table
0|0|0|USE TEMP B-TREE FOR ORDER BY
Вы можете получить следующее ниже или выше значение, используя индекс, как это:
select min(value) from 'table' where x >= N;
select max(value) from 'table' where x <= N;
И вы можете использовать union
для получить как от одного запроса:
explain query plan
select min(value) from 'table' where value >= 10
union select max(value) from 'table' where value <= 10;
1|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value>?)
2|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value<?)
0|0|0|COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)
Это будет довольно быстро даже на больших столах. Вы можете просто загрузить оба значения и оценивать их в коде, или использовать еще больше SQL, чтобы выбрать один различными способами:
explain query plan select v from
( select min(value) as v from 'table' where value >= 10
union select max(value) as v from 'table' where value <= 10)
order by abs(10-v) limit 1;
2|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value>?)
3|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value<?)
1|0|0|COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)
0|0|0|SCAN SUBQUERY 1
0|0|0|USE TEMP B-TREE FOR ORDER BY
или
explain query plan select 10+v from
( select min(value)-10 as v from 'table' where value >= 10
union select max(value)-10 as v from 'table' where value <= 10)
group by v having max(abs(v)) limit 1;
2|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value>?)
3|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value<?)
1|0|0|COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)
0|0|0|SCAN SUBQUERY 1
0|0|0|USE TEMP B-TREE FOR GROUP BY
Поскольку вы заинтересованы в значениях и произвольно больше и меньше, чем цель, вы не можете избежать выполнения двух запросов индекса. Если вы знаете, что цель находится в небольшом диапазоне, однако, вы можете использовать «между» только ударил индекс один раз:
explain query plan select * from 'table' where value between 9 and 11 order by abs(10-value) limit 1;
0|0|0|SEARCH TABLE table USING COVERING INDEX value_index (value>? AND value<?)
0|0|0|USE TEMP B-TREE FOR ORDER BY
Это будет примерно 2 раза быстрее, чем запрос накидной выше, когда он оценивает только 1 -2, но если вы начнете загружать больше данных, он быстро станет медленнее.
Имейте в виду, что система типа sqlite является специальной и имеет ли у вас истинный двойник ничего общего с объявлениями любого типа. – unmounted