Как выбрать лучший SQL-запрос, если есть разные способы выполнить одну и ту же задачу?

3

Я изучаю SQL (используя SQLite 3 и его инструмент командной строки sqlite3), и я заметил, что могу делать некоторые вещи несколькими способами, и иногда не ясно, какой из них лучше. Вот три запроса, которые выполняют одно и то же: одно выполняется через intersect, другое через inner join и distinct, последнее похожее на второе, но включает фильтрацию через where. (Первая была написана автором книги, которую я читаю, а остальные я написал сам.)

Вопрос в том, , какой из этих запросов лучше и почему? И, в более общем смысле, , как я могу узнать, когда один запрос лучше другого? Есть ли какие-то рекомендации, которые я пропустил, или, возможно, я должен изучить внутренние элементы SQLite, несмотря на декларативный характер SQL?

(В следующем примере есть таблицы, которые описывают имена продуктов, упомянутые в некоторых сериалах. Foods_episodes - это таблица ссылок "многие-ко-многим", в то время как другие описывают имена продуктов и имена эпизодов вместе с номером сезона. разыгрываются десятки лучших продуктов (основанные на количестве их выступлений во всех сериях), а не только лучшие продукты в сезонах 3..5)

-- task
--     find the all-time top ten foods that appear in seasons 3 through 5
-- schema
--     CREATE TABLE episodes (
--       id integer primary key,
--       season int,
--       name text );
--     CREATE TABLE foods(
--       id integer primary key,
--       name text );
--     CREATE TABLE foods_episodes(
--       food_id integer,
--       episode_id integer );



select f.* from foods f 
inner join 
    (select food_id, count(food_id) as count 
        from foods_episodes 
        group by food_id 
        order by count(food_id) desc limit 10) top_foods 
    on f.id=top_foods.food_id 
intersect 
select f.* from foods f 
    inner join foods_episodes fe on f.id = fe.food_id 
    inner join episodes e on fe.episode_id = e.id 
where
    e.season between 3 and 5 
order by
    f.name; 



select
    distinct f.*
from
    foods_episodes as fe
    inner join episodes as e on e.id = fe.episode_id
    inner join foods as f on fe.food_id = f.id
    inner join (select food_id from foods_episodes
        group by food_id order by count(*) desc limit 10) as lol
        on lol.food_id = fe.food_id
where
    e.season between 3 and 5
order by 
    f.name;



select
    distinct f.*
from
    foods_episodes as fe
    inner join episodes as e on e.id = fe.episode_id
    inner join foods as f on fe.food_id = f.id
where
    fe.food_id in (select food_id from foods_episodes
        group by food_id order by count(*) desc limit 10)
    and e.season between 3 and 5
order by 
    f.name;

-- output (same for these thee):

-- id          name      
-- ----------  ----------
-- 4           Bear Claws
-- 146         Decaf Capp
-- 153         Hennigen's
-- 55          Kasha     
-- 94          Ketchup   
-- 164         Naya Water
-- 317         Pizza     
-- CPU Time: user 0.000000 sys 0.000000
Теги:

2 ответа

6
Лучший ответ

Подобно MySQL, похоже, что SQLlite имеет команду EXPLAIN. Подготовьте свой выбор с помощью ключевого слова EXPLAIN, и он вернет информацию о запросе, включая количество проверенных строк и используемые индексы.

http://www.sqlite.org/lang_explain.html

Запустив EXPLAIN для различных выборок, вы можете определить, какие запросы (и подзапросы) более эффективны, чем другие.

И вот общий обзор планировщика запросов SQLlite и оптимизации: http://sqlite.org/optoverview.html

SQLlite3 также поддерживает функцию обратного вызова для отслеживания запросов. Вы должны его реализовать, но: http://www.sqlite.org/c3ref/profile.html

  • 0
    +1 Когда два запроса возвращают одинаковые результаты, чем эффективнее, тем лучше.
  • 0
    Просто отметив комментарий, что часто, если вы пишете два разных запроса, EXPLAIN покажет вам, что движок игнорирует различия и фактически делает то же самое за кулисами.
Показать ещё 2 комментария
1

Как правило, существует более одного способа решения проблемы. Если вы получаете правильные ответы, единственный вопрос заключается в том, нужно ли улучшить процесс / script/, или если он хорошо работает сейчас.

В SQL обычно может быть "лучший" способ, но обычно это не цель найти канонический лучший способ сделать что-то - вы хотите, чтобы он эффективно сочетал ваши потребности с программой и ваше время. может потратить месяцы на оптимизацию процесса, но если этот процесс используется только еженедельно, и это займет всего 5 минут, сокращение его до 4 минут не очень помогает.

Странно переходить из контекста, где есть правильные ответы (например, школа), в контексте, где цель состоит в том, чтобы сделать что-то хорошо, и хорошо работает на козырях, потому что есть временные ограничения. Это то, что мне понадобилось, чтобы оценить, но я не уверен, что есть лучший ответ. Надеюсь, что перспектива немного помогает!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню