› MySQL 5.5 Community Server
› MySQL 5.6 Community Server
› Percona Configuration Wizard
› XtraBackup 搭建主从复制
Great Sites on MySQL
› Percona
› MySQL Performance Blog
› Severalnines
推荐管理工具
› Sequel Pro
› phpMyAdmin
推荐书目
› MySQL Cookbook
MySQL 相关项目
› MariaDB
› Drizzle
参考文档
› http://mysql-python.sourceforge.net/MySQLdb.html
j0hnj
V2EX  ›  MySQL

为什么这个 SQL 语句做了全表扫描?

  •  
  •   j0hnj · Mar 15, 2018 · 4425 views
    This topic created in 3122 days ago, the information mentioned may be changed or developed.

    表结构是这样的:

    CREATE TABLE user (
      id       INT PRIMARY KEY AUTO_INCREMENT,
      username CHAR(10) UNIQUE
    );
    CREATE TABLE business (
      id      INT PRIMARY KEY AUTO_INCREMENT,
      user_id INT NOT NULL,
      FOREIGN KEY (user_id) REFERENCES user (id)
    );
    CREATE TABLE asset (
      id          INT PRIMARY KEY AUTO_INCREMENT,
      business_id INT NOT NULL,
      FOREIGN KEY (business_id) REFERENCES business (id)
    );
    CREATE TABLE task (
      id       INT PRIMARY KEY AUTO_INCREMENT,
      asset_id INT NOT NULL,
      FOREIGN KEY (asset_id) REFERENCES asset (id)
    );
    CREATE TABLE problem (
      id INT PRIMARY KEY AUTO_INCREMENT
    );
    CREATE TABLE result (
      id         INT PRIMARY KEY AUTO_INCREMENT,
      task_id    INT NOT NULL,
      problem_id INT NOT NULL,
      FOREIGN KEY (task_id) REFERENCES task (id),
      FOREIGN KEY (problem_id) REFERENCES problem (id)
    );
    

    这是查询语句:

    EXPLAIN SELECT
            problem.*,
            business.*
          FROM user
            INNER JOIN business
            INNER JOIN asset
            INNER JOIN task
            INNER JOIN result
            INNER JOIN problem
              ON (user.username = 'user1' AND
                  business.user_id = user.id AND
                  asset.business_id = business.id AND
                  task.asset_id = asset.id AND
                  result.task_id = task.id AND
                  problem.id = result.problem_id
              )
          GROUP BY problem.id, business.id;
    

    这是输出结果:

    +----+-------------+----------+------------+--------+---------------------+----------+---------+-----------------------+------+----------+----------------------------------------------------+
    | id | select_type | table    | partitions | type   | possible_keys       | key      | key_len | ref                   | rows | filtered | Extra                                              |
    +----+-------------+----------+------------+--------+---------------------+----------+---------+-----------------------+------+----------+----------------------------------------------------+
    | 1  | SIMPLE      | user     | <null>     | const  | PRIMARY,username    | username | 11      | const                 | 1    | 100.0    | Using index; Using temporary; Using filesort       |
    | 1  | SIMPLE      | problem  | <null>     | index  | PRIMARY             | PRIMARY  | 4       | <null>                | 5    | 100.0    | Using index                                        |
    | 1  | SIMPLE      | result   | <null>     | ALL    | task_id,problem_id  | <null>   | <null>  | <null>                | 6    |  25.0    | Using where; Using join buffer (Block Nested Loop) |
    | 1  | SIMPLE      | task     | <null>     | eq_ref | PRIMARY,asset_id    | PRIMARY  | 4       | tmp.result.task_id    | 1    | 100.0    | <null>                                             |
    | 1  | SIMPLE      | asset    | <null>     | eq_ref | PRIMARY,business_id | PRIMARY  | 4       | tmp.task.asset_id     | 1    | 100.0    | <null>                                             |
    | 1  | SIMPLE      | business | <null>     | eq_ref | PRIMARY,user_id     | PRIMARY  | 4       | tmp.asset.business_id | 1    |  50.0    | Using where                                        |
    +----+-------------+----------+------------+--------+---------------------+----------+---------+-----------------------+------+----------+----------------------------------------------------+
    

    从结果的第三行可以看出,MySQL 对 result 表做了全表扫描,这是为什么了?

    5 replies  •  2018-03-15 20:55:04 +08:00
    F281M6Dh8DXpD1g2
        1
    F281M6Dh8DXpD1g2  
       Mar 15, 2018
    什么是 CBO 了解一下
    skyleft
        2
    skyleft  
       Mar 15, 2018
    user.username = 'user1' 应该放在外面 加 where 里吧
    j0hnj
        3
    j0hnj  
    OP
       Mar 15, 2018
    @skyleft on 其实跟 where 没有区别,mysql 处理后都是 where
    jusalun
        4
    jusalun  
       Mar 15, 2018
    你好歹把测试数据也给出来啊,你只给出结构定义和 sql,我自己造的数据打执行计划全走索引了啊

    1 SIMPLE user const PRIMARY,username username 41 const 1 100 Using index; Using temporary; Using filesort
    1 SIMPLE business ref PRIMARY,user_id user_id 4 const 1 100 Using index
    1 SIMPLE asset ref PRIMARY,business_id business_id 4 test_db.business.id 1 100 Using index
    1 SIMPLE task ref PRIMARY,asset_id asset_id 4 test_db.asset.id 1 100 Using index
    1 SIMPLE result ref task_id,problem_id task_id 4 test_db.task.id 1 100
    1 SIMPLE problem eq_ref PRIMARY PRIMARY 4 test_db.result.problem_id 1 100 Using index
    sizhitu
        5
    sizhitu  
       Mar 15, 2018
    是不是 result 表数据量比较小,全表扫描比走索引的效率高?
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   874 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 19:05 · PVG 03:05 · LAX 12:05 · JFK 15:05
    ♥ Do have faith in what you're doing.