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
对于给定的两种情况:

  • DB引擎如何决定首先搜索
    电影
    表,然后搜索
    角色

  • 为什么在第二种情况下DB engine
    SCAN
    ning
    movie
    表?而不是
    搜索


  • 不是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>