Имеет ли значение порядок составного индекса базы данных, если первый столбец запрашивается только с помощью операции равенства?

Вопрос: если у меня есть таблица Orders с индексом (UserId, CreatedTime), имеет ли значение добавление DESC к CreatedTime, если я хочу перечислить заказы только одного пользователя?

Например:

SELECT * 
FROM Orders -- Also potentially have row limit
WHERE UserId = @UserId
ORDER BY CreatedTime DESC; 

Чего я не понимаю, так это того, что если ответ положительный, то почему БД не может просто начать снизу и идти вверх, поскольку она уже знает диапазон @UserId?

Кроме того, я работаю как с SQL Server, так и с SQLite, поэтому мне было бы интересно узнать, будет ли ответ отличаться для каждой СУБД.

Я до сих пор не очень понимаю Индексы SQL Server - по возрастанию или по убыванию, какая разница? и, видимо, в MongoDB, это не имеет значения (Имеет ли значение порядок индексов в MongoDB?).

Возвращаясь к приведенному выше запросу, даже если бы мне пришлось перечислить всех пользователей и соответствующие им порядки в порядке убывания CreatedTime, почему база данных не может сделать это:

  • Для пользователя №1 строки расположены с №1 по №10, поэтому извлекайте строки с №1 по №10 в обратном порядке.
  • Для пользователя №2 строки расположены с №11 по №13, поэтому извлекайте строки с №11 по №13 в обратном порядке.
  • ...

Я даже спросил у ИИ, и он просто сказал мне, что извлечение снизу вверх происходит медленнее, без дальнейших объяснений, даже когда я пытался нажать на него.

🤔 А знаете ли вы, что...
SQL Server активно развивается и обновляется Microsoft с выпуском новых версий и обновлений с новыми возможностями и улучшениями.


66
1

Ответ:

Решено

В SQLite индекс будет использоваться независимо от того, сортируете ли вы по CreatedTime по возрастанию или убыванию.

Данный:

create table orders (
  user_id integer,
  created_time integer
);

create index orders_index on orders (user_id, created_time);

Планы запросов для обоих типов идентичны:

sqlite> explain query plan select * from orders where user_id = 1 order by created_time;
QUERY PLAN
`--SEARCH orders USING COVERING INDEX orders_index (user_id=?)

sqlite> explain query plan select * from orders where user_id = 1 order by created_time desc;
QUERY PLAN
`--SEARCH orders USING COVERING INDEX orders_index (user_id=?)

Если вместо этого вы выполняете запрос диапазона по user_id, а затем сортируете по user_id, created_time, дополнительная временная таблица будет использоваться только в том случае, если created_time отсортировано в порядке убывания:

sqlite> explain query plan select * from orders where user_id > 1 order by user_id, created_time;
QUERY PLAN
`--SEARCH orders USING COVERING INDEX orders_index (user_id>?)

sqlite> explain query plan select * from orders where user_id > 1 order by user_id, created_time desc;
QUERY PLAN
|--SEARCH orders USING COVERING INDEX orders_index (user_id>?)
`--USE TEMP B-TREE FOR LAST TERM OF ORDER BY

Для этого запроса вам понадобится индекс для created_time desc:

create index orders_index_2 on orders (user_id, created_time desc);

=>

sqlite> explain query plan select * from orders where user_id > 1 order by user_id, created_time desc;
QUERY PLAN
`--SEARCH orders USING COVERING INDEX orders_index_2 (user_id>?)