3

我正在学习 SQL(使用 SQLite 3 及其sqlite3命令行工具),我注意到我可以通过多种方式做一些事情,有时并不清楚哪一种更好。这里有三个查询,它们做同样的事情,一个通过执行intersect,另一个通过inner joinand distinct,最后一个类似于第二个,但它包含过滤 through where。(第一个是我正在阅读的书的作者写的,其他是我自己写的。)

问题是,这些查询中哪个更好,为什么?而且,更一般地说,我怎么知道一个查询何时比另一个更好?是否有一些我错过的指导方针,或者尽管 SQL 具有声明性,我还是应该学习 SQLite 内部原理?

(在下面的示例中,有一些表描述了某些电视剧中提到的食物名称。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
4

2 回答 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

于 2012-06-11T19:59:46.437 回答
1

通常,解决问题的方法不止一种。如果您得到正确答案,那么唯一的另一个问题是流程/脚本/语句是否需要改进,或者它现在是否运行良好。

一般来说,在 SQL 中,可能有一种“最佳”方式,但通常不是寻找规范的最佳方式来做某事的目标——您需要一种有效平衡程序需求和时间的方式。您可以花几个月的时间优化流程,但如果流程只每周使用一次,现在只需要 5 分钟,那么将其减少到 4 分钟并没有多大帮助。

从一个有正确答案的环境(比如学校)过渡到一个目标是把事情做好,并且工作得足够好胜过完美的环境是很奇怪的,因为有时间限制。我花了一段时间才意识到这一点,但我不确定是否有更好的答案。希望观点有所帮助!

于 2012-06-11T21:42:04.743 回答