效用声明

最近更新时间: 2024-06-12 15:06:00

DESCRIBE 语句

DESCRIBE 用于获取表结构信息: 示例:

mysql> DESCRIBE City;
+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| Id         | int(11)  | NO   | PRI | NULL    | auto_increment |
| Name       | char(35) | NO   |     |         |                |
| Country    | char(3)  | NO   | UNI |         |                |
| District   | char(20) | YES  | MUL |         |                |
| Population | int(11)  | NO   |     | 0       |                |
+------------+----------+------+-----+---------+----------------+

EXPLAIN 语句

语法

{EXPLAIN | DESCRIBE | DESC}
    tbl_name [col_name | wild]

{EXPLAIN | DESCRIBE | DESC}
    [explain_type]
    {explainable_stmt | FOR CONNECTION connection_id}

{EXPLAIN | DESCRIBE | DESC} ANALYZE [FORMAT = TREE] select_statement

explain_type: {
    FORMAT = format_name
}

format_name: {
    TRADITIONAL
  | JSON
  | TREE
}

explainable_stmt: {
    SELECT statement
  | TABLE statement
  | DELETE statement
  | INSERT statement
  | REPLACE statement
  | UPDATE statement
}

注意:

查看执行计划,SQL不会真正执行

在只读的DB上,无法查看写SQL的执行计划

示例:

DROP TABLE if exists employees;
CREATE TABLE employees (
    id INT key NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired date,
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
shardkey=id;

MySQL [test]> explain select id,fname,lname from employees where id=20\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: NULL
   partitions: NULL
         type: NULL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
     filtered: NULL
        Extra: no matching row in const table
         info: set_1624363251_3, explain select id,fname,lname from `test`.`employees` where (id = 20) 
1 row in set (0.00 sec)

执行计划中各字段含义:

  • id:执行行顺序,按1,2,3,4…进行排序。在所有组中,id值越大,优先级越高,越先执行。id如果相同,可以认为是一组,从上往下顺序执行

  • select_type:select的类型。

  • table:输出记录的表,对应行正在访问哪一个表,表名或者别名,可能是临时表或者union合并结果集

  • partitions:符合的分区

  • type:显示的是访问类型,访问类型表示以何种方式去访问数据,例如全表扫描

  • possible_keys:优化器可能使用到的索引

  • key:优化器实际选择的索引

  • key_len:表示索引中使用的字节数,可以通过key_len计算查询中使用的索引长度

  • ref:显示索引的哪一列被使用了,如果可能的话,是一个常数

  • rows:优化器预估的记录数量,根据表的统计信息及索引使用情况,大致估算出找出所需记录需要读取的行数

  • filtered:该 filtered 列指示将按表条件过滤的表行的估计百分比。 最大值为100,这意味着不会对行进行过滤。 值从100开始减少表示过滤量增加

  • Extra:额外的显示选项

  • info:网关下推,记录了实际发往的set名称和sql信息,info这个一列信息是分布式实例执行计划特有的

网关下推示例

测试表准备

--创建测试表
drop table if exists t1;
create table t1(a int key, b int) shardkey=a;
drop table if exists t2;
create table t2(a int key, b int) shardkey=a;

--集群的结构,包含2个set

select 查询的下推

  1. 指定了shardkey的单表查询。根据shardkey的哈希值计算出目标set,然后将查询直接下推给目标set执行。

    -- info字段展示了发送的目标set,以及下推的查询
    MySQL [test]> explain select * From t1 where a=1\G;
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: NULL
       partitions: NULL
             type: NULL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: NULL
         filtered: NULL
            Extra: no matching row in const table
             info: set_1624363222_1, explain select * from `test`.`t1` where (a = 1) 
    1 row in set (0.00 sec)
  2. 未指定shardkey的单表查询。将查询广播给所有目标set执行。

    -- 广播给两个set执行,因此返回了两条记录,其中info字段展示了发送的目标set,以及下推的查询
    MySQL [test]> explain select * From t1 where b=1\G;
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: t1
       partitions: p0,p1,p2,p3,p4,p5,p6,p7
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 1
         filtered: 100.00
            Extra: Using where
             info: set_1624363222_1, explain select * from `test`.`t1` where (b = 1)
    *************************** 2. row ***************************
               id: 1
      select_type: SIMPLE
            table: t1
       partitions: p8,p9,p10,p11,p12,p13,p14,p15
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 1
         filtered: 100.00
            Extra: Using where
             info: set_1624363251_3, explain select * from `test`.`t1` where (b = 1)
    2 rows in set (0.01 sec)
  3. 多表连接查询。当shardkey相等时,将查询直接下推给db执行。

    -- 广播给两个set执行,因此返回了两条记录,其中info字段展示了发送的目标set,以及下推的查询
    -- shardkey相等,但shardkey未指定明确的值,因此广播给所有set执行。
    MySQL [test]> explain select * from t1, t2 where t1.a=t2.a;
    
    -- shardkey相等,且shardkey指定了明确的值,因此shardkey的哈希值转给目标set执行。
    MySQL [test]> explain select * from t1, t2 where t1.a=t2.a and t1.a=1;
    
    -- shardkey相等,且shardkey指定了多个明确的值,因此shardkey的哈希值转给多个目标set执行。
    MySQL [test]> explain select * from t1, t2 where t1.a=t2.a and t1.a in (1,2,3);
    
    -- shardkey相等,且shardkey指定了多个明确的值,但当前网关在计算shardkey的值时会忽略'or'谓词,因此将广播给所有set执行。
    MySQL [test]> explain select * from t1, t2 where t1.a=t2.a and (t1.a=1 or t1.a=2);
  4. 常用聚合函数,包括sum、count、avg、max以及min的下推。

    -- 网关将查询广播给所有set,并对set返回的聚合结果进行累加
    MySQL [test]> explain select count(1) from t1;
    
    -- 网关将avg转换为sum、count,并广播给所有set执行,再根据set返回的sum、count值计算出全局的avg
    MySQL [test]> explain select avg(a) from t1;
    
    -- 多表连接时,表的shardkey相等,网关将查询广播给所有set执行,并对set返回的聚合结果进行累加
    MySQL [test]> explain select sum(t1.a) from t1, t2 where t1.a=t2.a;
    
    -- 多表连接时,表的shardkey相等,且shardkey指定了明确的值,网关将查询转发给目标set执行
    MySQL [test]> explain select sum(t1.a) from t1, t2 where t1.a=t2.a and t1.a=1;
    
    -- 网关将查询广播给所有set执行,再对set返回的结果进行归并排序,计算出每个分组的全局sum值
    MySQL [test]> explain select sum(a) from t1 group by b\G;
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: t1
       partitions: p8,p9,p10,p11,p12,p13,p14,p15
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 1
         filtered: 100.00
            Extra: Using temporary; Using filesort
             info: set_1624363251_3, explain select sum(a),b, COLLATION(b) from `test`.`t1` group by b order by b
    *************************** 2. row ***************************
               id: 1
      select_type: SIMPLE
            table: t1
       partitions: p0,p1,p2,p3,p4,p5,p6,p7
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 1
         filtered: 100.00
            Extra: Using temporary; Using filesort
             info: set_1624363222_1, explain select sum(a),b, COLLATION(b) from `test`.`t1` group by b order by b
    2 rows in set (0.00 sec)
  5. distinct的下推。

    -- 将distinct下推给set执行,同时额外追加order by操作。网关对set返回的有序元组进行归并排序和去重,从而得到全局去重的结果。
    MySQL [test]> explain select distinct b from t1\G;
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: t1
       partitions: p8,p9,p10,p11,p12,p13,p14,p15
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 1
         filtered: 100.00
            Extra: Using temporary; Using filesort
             info: set_1624363251_3, explain select distinct b from `test`.`t1` order by b
    *************************** 2. row ***************************
               id: 1
      select_type: SIMPLE
            table: t1
       partitions: p0,p1,p2,p3,p4,p5,p6,p7
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 1
         filtered: 100.00
            Extra: Using temporary; Using filesort
             info: set_1624363222_1, explain select distinct b from `test`.`t1` order by b
    2 rows in set (0.00 sec)
  6. 子查询的下推。

    -- 通过等值传递,能够推断出父查询和子查询中表的shardkey相等时,则网关将查询下推给db执行。
    -- 注意:由于实现方式的不同,部分查询的explain的结果为json的形式。其中DBQuery字段描述了下推到db执行的查询。
    -- IN子查询
    MySQL [test]> explain select * from t1 where t1.a in (select a from t2)\G;
    *************************** 1. row ***************************
    trace: [
       {
          "ProxyDeduplicate " : "false",
          "Query" : "set_1624363222_1 set_1624363251_3  , Select `t1`.`a`, `t1`.`b` from `test`.`t1` where (`test`.`t1`.`a`) in (select `test`.`t2`.`a` from `test`.`t2`)",
          "QueryMode" : "Hash"
       }
    ]
    
    -- EXISTS 子查询
    MySQL [test]> explain select * from t1 where exists (select * From t2 where t1.a=t2.a)\G;
    *************************** 1. row ***************************
    trace: [
       {
          "ProxyDeduplicate " : "false",
          "Query" : "set_1624363222_1 set_1624363251_3  , Select `t1`.`a`, `t1`.`b` from `test`.`t1` where exists(select 1 from `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`))",
          "QueryMode" : "Hash"
       }
    ]
    
    -- 通过等值传递,能够推断出父查询和子查询中表的shardkey相等时,则网关将查询下推给db执行。
    MySQL [test]> explain select * from t1 where t1.a in (select b from t2 where t2.a=t2.b)\G;
    *************************** 1. row ***************************
    trace: [
       {
          "ProxyDeduplicate " : "false",
          "Query" : "set_1624363222_1 set_1624363251_3  , Select `t1`.`a`, `t1`.`b` from `test`.`t1` where (`test`.`t1`.`a`) in (select `test`.`t2`.`b` from `test`.`t2` where (`test`.`t2`.`a` = `test`.`t2`.`b`))",
          "QueryMode" : "Hash"
       }
    ]
  7. distinct聚合函数的下推,例如count(distinct 表达式)、sum(distinct 表达式)等。

    -- 不存在分组(group by)和排序(order by)操作时,网关只下推distinct查询给所有set执行.
    -- 网关对set返回的结果再次去重,从而计算count(distinct b)的值。
    MySQL [test]> explain select count(distinct b) from t1 \G
    *************************** 1. row ***************************
    trace: [
       {
          "AggFunc " : "count(distinct `test`.`t1`.`b`)",
          "ProxyDeduplicate " : "false",
          "Query" : "set_1624363222_1 set_1624363251_3  , Select DISTINCT `t1`.`b` from `test`.`t1` where 1",
          "QueryMode" : "Hash"
       }
    ]
    
    -- 当存在分组(group by)操作时,网关下推distinct操作,并在下推的查询中额外添加order by语句。
    -- 网关对set返回的有序元组按照'分组列'进行归并排序,并计算每个分组的聚合函数count(distinct b)的值。
    MySQL [test]> explain select count(distinct b) from t1 group by a\G
    *************************** 1. row ***************************
    trace: [
       {
          "AggFunc " : "count(distinct `test`.`t1`.`b`)",
          "DBGroupColumns " : "`test`.`t1`.`a`",
          "DBSortedColumns " : "`test`.`t1`.`a`",
          "ProxyDeduplicate " : "false",
          "Query" : "set_1624363222_1 set_1624363251_3  , Select DISTINCT `t1`.`a`, `t1`.`b`, `test`.`t1`.`a` from `test`.`t1` where 1 order by 3",
          "QueryMode" : "Hash"
       }
    ]
    
    -- 当同时存在分组(group by)以及排序(order by)操作时,网关按照前面的例子先计算出分组聚合操作的结果,再利用临时表对分组聚合的结果进行排序。
    -- 其中PorxyTmptable字段展示了创建的临时表;ProxyQuery展示了需要在临时表上执行的查询。
    MySQL [test]> explain select a, count(distinct b) as cnt from t1 group by a order by cnt \G
    *************************** 1. row ***************************
    trace: [
       {
          "AggFunc " : "count(distinct `test`.`t1`.`b`)",
          "DBGroupColumns " : "`test`.`t1`.`a`",
          "DBSortedColumns " : "`test`.`t1`.`a`",
          "ProxyDeduplicate " : "false",
          "ProxyQuery" : "SELECT f0 ,f1  FROM proxy_tmpdb.tmptbl  ORDER BY f1  ",
          "ProxySortedColumns " : "count(distinct `test`.`t1`.`b`)",
          "ProxyTmptable" : "CREATE TEMPORARY TABLE proxy_tmpdb.tmptbl (f0 int(11),f1  bigint)",
          "Query" : "set_1624363222_1 set_1624363251_3  , Select DISTINCT `t1`.`a`, `t1`.`b`, `test`.`t1`.`a` from `test`.`t1` where 1 order by 3",
          "QueryMode" : "Hash"
       }
    ]

    Delete/update的下推

  8. 指定了shardkey值的单表查询。

    -- 网关根据shardkey的值计算出目标set,并将查询直接下推给目标set。
    -- 注意:info字段展示了目标set以及下推的查询语句
    MySQL [test]> explain delete from t1 where a=1\G
    *************************** 1. row ***************************
               id: 1
      select_type: DELETE
            table: t1
       partitions: p1
             type: range
    possible_keys: PRIMARY
              key: PRIMARY
          key_len: 4
              ref: const
             rows: 1
         filtered: 100.00
            Extra: Using where
             info: set_1624363222_1, explain delete from `test`.`t1` where (a = 1)
    
    MySQL [test]> explain update t1 set b=1 where a=1\G
    *************************** 1. row ***************************
               id: 1
      select_type: UPDATE
            table: t1
       partitions: p1
             type: range
    possible_keys: PRIMARY
              key: PRIMARY
          key_len: 4
              ref: const
             rows: 1
         filtered: 100.00
            Extra: Using where
             info: set_1624363222_1, explain update `test`.`t1` SET b=1 where (a = 1)
  9. 没有指定shardkey值的单表查询。

    -- 将查询广播给所有set。
    -- 注意:info字段展示了目标set以及下推的查询语句
    MySQL [test]> explain delete from t1 where 1\G
    *************************** 1. row ***************************
               id: 1
      select_type: DELETE
            table: t1
       partitions: p0,p1,p2,p3,p4,p5,p6,p7
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 1
         filtered: 100.00
            Extra: NULL
             info: set_1624363222_1, explain delete  from `test`.`t1` where 1
    *************************** 2. row ***************************
               id: 1
      select_type: DELETE
            table: t1
       partitions: p8,p9,p10,p11,p12,p13,p14,p15
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 1
         filtered: 100.00
            Extra: NULL
             info: set_1624363251_3, explain delete from `test`.`t1` where 1
    
    MySQL [test]> explain update t1 set b=1 where 1\G
    *************************** 1. row ***************************
               id: 1
      select_type: UPDATE
            table: t1
       partitions: p0,p1,p2,p3,p4,p5,p6,p7
             type: index
    possible_keys: NULL
              key: PRIMARY
          key_len: 4
              ref: NULL
             rows: 1
         filtered: 100.00
            Extra: NULL
             info: set_1624363222_1, explain update `test`.`t1` SET b=1 where 1
    *************************** 2. row ***************************
               id: 1
      select_type: UPDATE
            table: t1
       partitions: p8,p9,p10,p11,p12,p13,p14,p15
             type: index
    possible_keys: NULL
              key: PRIMARY
          key_len: 4
              ref: NULL
             rows: 1
         filtered: 100.00
            Extra: NULL
             info: set_1624363251_3, explain update `test`.`t1` SET b=1 where 1
  10. 多表更新操作,且表的shardkey相等。

    -- 多表更新操作,且shardkey相等时,网关将查询直接下推给后端set执行。
    -- 如果shardkey为一个明确的值,则根据shardkey的值计算出目标set;否则,将查询广播给所有set执行。
    MySQL [test]> explain update t1, t2 set t1.b=t2.b where t1.a=t2.a and t1.a=202\G
    *************************** 1. row ***************************
              id: 1
     select_type: UPDATE
           table: NULL
      partitions: NULL
            type: NULL
    possible_keys: NULL
             key: NULL
         key_len: NULL
             ref: NULL
            rows: NULL
        filtered: NULL
           Extra: no matching row in const table
            info: set_1624363222_1, explain update `test`.`t1` join `test`.`t2` SET t1.b=t2.b where ((t1.a = t2.a) and (t1.a = 202))
  11. 多表更新操作,且表的shardkey不相等,或者包含子查询。网关将构建与更新操作对应的select查询,计算出被更新行的主键、被更新列的新值,再构建相应的update语句发送给set执行。因此,其下推策略同select查询

    -- 对于如下查询,网关将构建与之对应的select查询:
    --      select * from t1, t2 where t1.a=1 and t2.a=21 and t1.b != t2.b group by t1.a;
    -- 然后再根据执行的结果,为t1中需要被更新的每个元组构建如下查询给set执行:
    --      update t1 set t1.b=... where t1.a= ...
    MySQL [test]> explain update t1, t2 set t1.b=t2.b where t1.a=1 and t2.a=21\G
    *************************** 1. row ***************************
    trace: [
      {
         "optype" : "TableRename",
         "t1" : "T2e(a,b)",
         "t2" : "T6(a,b)",
         "timecost" : "0.031000"
      },
      {
         "0.OpType         " : "Load table",
         "1.TableName      " : "T6",
         "2.PushedDownCond " : "( /*filter*/((`test`.`t2`.`a`=21)))",
         "3.NumOfRows      " : "0",
         "4.AddedCond      " : "`test`.`t2`.`a` is null",
         "Query" : "set_1624363251_3  , select `a`,`b` from `test`.`t2` t2 where ( /*filter*/((`test`.`t2`.`a`=21))) limit 1000",
         "QueryMode" : "Hash",
         "timecost" : "0.640000"
      },
      {
         "0.OpType         " : "Load table",
         "1.TableName      " : "T2e",
         "2.PushedDownCond " : "(0)",
         "3.NumOfRows      " : "0",
         "4.AddedCond      " : "`test`.`t1`.`a` is null",
         "Query" : "AllSets , select `a`,`b` from `test`.`t1` t1 where (0) limit 1000",
         "QueryMode" : "All",
         "timecost" : "0.544000"
      },
      {
         "Query" : " select `test`.`t1`.`a`,`test`.`t1`.`b`,`test`.`t2`.`b` from `test`.`T2e` `t1` join `test`.`T6` `t2` where 0 group by `test`.`t1`.`a` for update of `test`.`t1`  ",
         "timecost" : "0.001000"
      }
    ]

USE 语句

语法如下:

use db_name

示例:

MySQL [test]> USE db1; 
MySQL [test]> SELECT COUNT(*) FROM mytable;           
MySQL [test]> USE db2; SELECT COUNT(*) FROM mytable;