Sql DB引擎如何决定联接操作的查询计划?
使用以下模式:Sql DB引擎如何决定联接操作的查询计划?,sql,sqlite,indexing,query-optimization,Sql,Sqlite,Indexing,Query Optimization,使用以下模式: sqlite> sqlite> sqlite> .schema CREATE TABLE movie ( id INTEGER PRIMARY KEY, title TEXT, year INTEGER, nth TEXT, for_video BOOLEAN ); CREATE TABLE actor ( id INTEGER PRIMARY KEY, name TEXT, gender TEXT ); CREATE TABLE role
sqlite>
sqlite>
sqlite> .schema
CREATE TABLE movie (
id INTEGER PRIMARY KEY, title TEXT, year INTEGER, nth TEXT, for_video BOOLEAN
);
CREATE TABLE actor (
id INTEGER PRIMARY KEY, name TEXT, gender TEXT
);
CREATE TABLE role (
movie_id INTEGER, actor_id INTEGER, name TEXT
);
CREATE TABLE sqlite_stat1(tbl,idx,stat);
sqlite>
在两个表上运行
JOIN
,如下所示:
sqlite> select * from movie JOIN role ON (movie.id = role.movie_id) WHERE movie.title='Batman' LIMIT 1;
"id" "title" "year" "nth" "for_video" "movie_id" "actor_id" "name"
"47844" "Batman" "1989" "" "0" "47844" "84264" "Napier Hood"
sqlite>
为了提高性能,我添加了以下索引:
sqlite> create index id1 on role(movie_id);
sqlite>
sqlite>
sqlite> create index id2 on movie(title);
sqlite>
sqlite>
然后查询计划说: 案例1 案例2
对于给定的两种情况:
电影
表,然后搜索角色
表
SCAN
ningmovie
表?而不是搜索
不是MySQL特定的,所以如果MySQL绝对低于PAR,那么它更像“在语句中的左到右”。
通常,任何databsae服务器都有统计信息,并估计它将为给定的过滤器返回多少行,然后它尝试各种方法(所有方法都基于这些统计信息),以查看哪种方法最有效。然后它执行这个。当您按Movie.Title进行筛选时,它很可能会先执行此操作,然后在另一个表中找到匹配的行 DB引擎如何决定首先搜索电影表,然后搜索角色表 您的WHERE
子句根据电影的标题要求电影,并且有一个索引,因此首先只获取具有该标题的电影,然后获取它们的ID,然后获取具有这些ID的角色(也有索引查找),然后将几个结果合并在一起肯定是有意义的
反过来说就没什么意义了:把所有的80000部电影和1000个不同的角色联系起来,列出80000个电影角色的列表,然后把它们都扔掉,除了标题为X的那一个
这是一个关于特定数据库如何规划这个特定查询的极其简单的观点;有许多不同的方式可以计划和执行查询。解释优化器/规划师采取的每一步和每一个决策都远远超出了SO答案的范围
对于第二种情况,SQLite似乎得出了这样的结论:它必须通过未索引的内容进行搜索,并且必须返回两位数据;有索引的和没有索引的。它决定了一种策略,将所有电影标题从索引中而不是从表中取出(索引可以提供标题,SQLite更愿意使用它来检索数据,而不是从表中),根据角色中的电影id索引将电影连接到角色,然后过滤所有工作,只留下亚瑟王的角色名和相关的电影标题
为什么DB引擎在第二种情况下扫描电影表?而不是搜索
它不是在搜索表,而是在扫描索引,它在执行扫描,因为查询不要求任何已索引的内容,所以必须检索并比较每个值以查找您要查找的内容我在查询中添加了另一个案例,尽管我在角色
上给出了where子句,但它首先适用于电影
我们是否会有这样一个问题,你问,我们回答,然后你编辑一点问题,我们编辑一点答案,然后你再次移动球门柱,然后我们转一圈又一圈?因为如果是的话,我希望你能阅读这本关于查询规划的手册——你是使用MySQL还是SQLite?@jarlh am使用SQLite
sqlite> EXPLAIN QUERY PLAN select * from movie JOIN role ON (movie.id = role.movie_id) WHERE movie.title='Batman' LIMIT 1;
"selectid" "order" "from" "detail"
"0" "0" "0" "SEARCH TABLE movie USING INDEX id2 (title=?)"
"0" "1" "1" "SEARCH TABLE role USING INDEX id1 (movie_id=?)"
sqlite> EXPLAIN QUERY PLAN select movie.title, role.name from movie JOIN role ON (movie.id = role.movie_id)
...> WHERE role.name = 'King Arthur' LIMIT 2;
"selectid" "order" "from" "detail"
"0" "0" "0" "SCAN TABLE movie USING COVERING INDEX id2"
"0" "1" "1" "SEARCH TABLE role USING INDEX id1 (movie_id=?)"
sqlite>
sqlite>