• Mysql优化


    Mysql优化

    版本

    select @@version;
    select version();
    5.7.23

    一、准备Sql

    1、创建表结构

    t_test:
    DROP TABLE IF EXISTS `t_test`;
    CREATE TABLE `t_test`  (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `user_id` int(11) NULL DEFAULT NULL,
      `user_level` int(1) NULL DEFAULT NULL,
      `type` int(255) NULL DEFAULT NULL,
      `y_score` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `t_score` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    SET FOREIGN_KEY_CHECKS = 1;

    user_id字段添加唯一索引;type字段添加普通索引

    ALTER TABLE `db_cold`.`t_test` 
    ADD UNIQUE INDEX `idx_user_id`(`user_id`) USING BTREE;
    
    ALTER TABLE `db_cold`.`t_test` 
    ADD INDEX `idx_type`(`type`) USING BTREE;
    t_type:
    -- ----------------------------
    -- Table structure for t_type
    -- ----------------------------
    DROP TABLE IF EXISTS `t_type`;
    CREATE TABLE `t_type`  (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `type_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of t_type
    -- ----------------------------
    INSERT INTO `t_type` VALUES (1, '类型1');

    2、使用存储过程插入1w条数据

    CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_auto_insertdata`( IN `rownum` INT )
    BEGIN
        DECLARE
            index_num INTEGER DEFAULT 1;
        WHILE
                index_num <= rownum DO
                -- insert
                INSERT INTO `db_cold`.`t_test` (`user_id`, `user_level`, `type`, `y_score`, `t_score` )
            VALUES
                (
                    index_num + 1,
                    IF(index_num <= rownum/2, 10, 20),
                    CASE index_num%3
                        WHEN 0 THEN 0
                        WHEN 1 THEN 1
                        WHEN 2 THEN 2
                        ELSE
                            10
                    END,
                    CONCAT( "Y", index_num + 10 ),
                    CONCAT( "T", index_num + 100 ) 
                );
            
            SET index_num = index_num + 1;
            
        END WHILE;
    END
    CALL proc_auto_insertdata ( 10000 )
    > OK
    > 时间: 348.543s

    二、使用Explain分析SQL 

    1、Explain的一些内容

     参考 https://segmentfault.com/a/1190000008131735

    示例:

    mysql> EXPLAIN select * from t_test t where 1=1 and t.type = 1G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t partitions: NULL type: ref possible_keys: idx_type key: idx_type key_len: 5 ref: const rows: 3334 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec)

     1.1 select_type

    1.1.1

    EXPLAIN select * from t_test t;
    id    select_type    table
    1      SIMPLE      t

       SIMPLE,单表查询。

    1.1.2

    EXPLAIN SELECT * FROM t_test t1 WHERE t1.type = ( SELECT t2.id FROM t_test t2 WHERE t2.id = 1 ); 
    id    select_type    table
    1    PRIMARY    t1
    2    SUBQUERY    t2

       t1外层查询 对应的是PRIMARY,t2子查询对应的是SUBQUERY

    1.1.3

    EXPLAIN select * from t_test t1 where t1.id=1 UNION select * from t_test t2 where t2.id=1;
    id    select_type    table
    1    PRIMARY    t1
    2    UNION    t2
        UNION RESULT    <union1,2>

       UNION左边(第一个SELECT)对应PRIMARY,UNION右边(第二个以及之后的查询)对应UNION,最后合并的操作对应UNION RESULT

    1.1.4

    EXPLAIN select * from t_test t1 where t1.id in (select t2.id from t_test t2 where t2.id=1  UNION select t3.id from t_test t3 where t3.id=2 );
    id    select_type        table
    1    PRIMARY           t1
    2    DEPENDENT SUBQUERY    t2
    3    DEPENDENT UNION       t3
        UNION RESULT      <union2,3>

       in 查询的子查询(下划线部分)与1.1.3一致,对于整个查询而言,子查询的PRIMARY是整个查询的DEPENDENT SUBQUERY,子查询的UNION是整个查询的DEPENDENT UNION,DEPENDENT SUBQUERY和DEPENDENT UNION都依赖于外层的结果,原因在与Mysql优化器会自动优化上面的语句为 :

    select * from t_test t1 where t1.id in (select t2.id from t_test t2 where t2.id=1 and t1.id=t2.id UNION select t3.id from t_test t3 where t3.id=2 and t1.id=t3.id);

     也就说明了子查询的subquery和union确实依赖于外层的sql

    1.2 type(参考 https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-join-types)

    执行效率从低到高: all < index < range < index_subquery < unique_subquery < index_merge < ref_or_null < ref < eq_ref < const<system

    1.2.1 null

    MySQL不访问任何表或索引,直接返回结果

    
    
    EXPLAIN select 1;
    EXPLAIN select CURRENT_DATE();
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE                                                                              No tables used

    1.2.1 const/system 

    单条记录,系统会把匹配行中的其他列作为常数处理,如主键或唯一索引查询。

    system是const的特例,表中只有一行数据。

    主键索引:

    EXPLAIN select * from t_test t where 1=1 and t.id = 2;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t                    const    PRIMARY    PRIMARY    4    const    1    100.00    

    唯一索引:

    EXPLAIN select * from t_test t where 1=1 and t.user_id = 2;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t                    const    idx_user_id    idx_user_id    5    const    1    100.00    

    1.2.2 eq_ref

    SQL_1_1:

    EXPLAIN SELECT
        t1.* 
    FROM
        t_test t1,
        t_type t2 
    WHERE
        1 = 1 
        AND t1.id = t2.id;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t2        index    PRIMARY    PRIMARY    4        2    100.00    Using index
    1    SIMPLE    t1        eq_ref    PRIMARY    PRIMARY    4    db_cold.t2.id    1    100.00    

    SQL_1_2:相比SQL_1_1,多了t1 字段 type的过滤条件

    EXPLAIN SELECT
        t1.* 
    FROM
        t_test t1,
        t_type t2 
    WHERE
        1 = 1 
        AND t1.id = t2.id 
        AND t1.type = 1;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t2        index    PRIMARY    PRIMARY    4        2    100.00    Using index
    1    SIMPLE    t1        eq_ref    PRIMARY,idx_type    PRIMARY    4    db_cold.t2.id    1    32.91    Using where

    SQL_2:

    EXPLAIN SELECT
        t2.* 
    FROM
        t_type t1,
        t_test t2 
    WHERE
        1 = 1 
        AND t1.id = t2.id 
        AND t2.type = 1;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t1        index    PRIMARY    PRIMARY    4        2    100.00    Using index
    1    SIMPLE    t2        eq_ref    PRIMARY,idx_type    PRIMARY    4    db_cold.t1.id    1    32.91    Using where

    left join

    SQL_3:

    EXPLAIN SELECT
        t1.* 
    FROM
        t_test t1
        LEFT JOIN t_type t2 ON t1.id = t2.id 
    WHERE
        1 = 1;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t1        ALL                    10130    100.00    
    1    SIMPLE    t2        eq_ref    PRIMARY    PRIMARY    4    db_cold.t1.id    1    100.00    Using index

    SQL_4:

    EXPLAIN SELECT
        t1.* 
    FROM
        t_test t1
        LEFT JOIN t_type t2 ON t1.id = t2.id 
    WHERE
        1 = 1
        AND t1.type = 3;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t1        ref    idx_type    idx_type    5    const    1    100.00    
    1    SIMPLE    t2        eq_ref    PRIMARY    PRIMARY    4    db_cold.t1.id    1    100.00    Using index

    总结:

    以下面的执行计划为例

    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t1        ref    idx_type    idx_type    5    const    1    100.00    
    1    SIMPLE    t2        eq_ref    PRIMARY    PRIMARY    4    db_cold.t1.id    1    100.00    Using index

    前面t1的每一行数据,t2(type==eq_ref)表中都有唯一的一行记录与之匹配,t1和t2链接规则为主键索引或者不为null的唯一索引。

    1.2.3 ref

    单表:

    EXPLAIN SELECT * FROM t_test t WHERE t.type = 1;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE        t                ref    idx_type    idx_type    5    const    3334    100.00    

    多表:

    EXPLAIN SELECT
        * 
    FROM
        t_test t1
        LEFT JOIN t_type t2 ON t1.type = t2.id 
    WHERE
        1 = 1 
        AND t1.type = 1;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t1        ref    idx_type    idx_type    5    const    3334    100.00    
    1    SIMPLE    t2        const    PRIMARY    PRIMARY    4    const    1    100.00    

    总结:type为 ref 表示 匹配当前表中的多行数据

    1.2.2 index

    最典型的就是查询的列是索引列

    EXPLAIN SELECT
        t.type 
    FROM
        t_test t 
    WHERE
        1 = 1;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t        index        idx_type    5        10130    100.00    Using index

    1.2.1 all

    全表扫描

    EXPLAIN SELECT
        * 
    FROM
        t_test t 
    WHERE
        1 = 1
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t        ALL                    10130    100.00     

    1.2.1 range(封闭区间检索,只使用<或者>不会使用Range)

     唯一索引:

    BETWEEN(range)

    EXPLAIN SELECT
        * 
    FROM
        t_test t 
    WHERE
        1 = 1 
        AND t.user_id BETWEEN 1 AND 2;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t        range    idx_user_id    idx_user_id    5        1    100.00    Using index condition

    IN(range)

    EXPLAIN SELECT
        * 
    FROM
        t_test t 
    WHERE
        1 = 1 
        AND t.user_id IN ( 1, 2 );
    1    SIMPLE    t        range    idx_user_id    idx_user_id    5        2    100.00    Using index condition

    < >(range)

    EXPLAIN SELECT
        * 
    FROM
        t_test t 
    WHERE
        1 = 1 
        AND t.user_id > 10 
        AND t.user_id < 100;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t        range    idx_user_id    idx_user_id    5        89    100.00    Using index condition

    普通索引:

    BETWEEN(all)

    EXPLAIN SELECT
        * 
    FROM
        t_test t 
    WHERE
        1 = 1 
        AND t.type BETWEEN 1 AND 2;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t        ALL    idx_type                10130    65.81    Using where

    IN(all)

    EXPLAIN SELECT
        * 
    FROM
        t_test t 
    WHERE
        1 = 1 
        AND t.type IN ( 1, 2 );
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t        ALL    idx_type                10130    65.81    Using where

    < >(range)

    EXPLAIN SELECT
        * 
    FROM
        t_test t 
    WHERE
        1 = 1 
        AND t.type > 10 
        AND t.type < 100;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t        range    idx_type    idx_type    5        1    100.00    Using index condition

    非主键 开区间检索:> 或者<

    EXPLAIN SELECT
        * 
    FROM
        t_test t 
    WHERE
        1 = 1 
        AND t.user_id > 10;
    id    select_type    table    partitions    type    possible_keys    key    key_len    ref    rows    filtered    Extra
    1    SIMPLE    t        ALL    idx_user_id                10130    98.63    Using where

    主键索引:

    type   SQL
    const:     EXPLAIN select * from t_test t where 1=1 and t.id = 1;
    range:     EXPLAIN select * from t_test t where 1=1 and t.id > 1;
    range:     EXPLAIN select * from t_test t where 1=1 and t.id >= 1;
    range:     EXPLAIN select * from t_test t where 1=1 and t.id < 1;
    range:     EXPLAIN select * from t_test t where 1=1 and t.id <= 1;
    range:     EXPLAIN select * from t_test t where 1=1 and t.id <> 1;
    range:     EXPLAIN select * from t_test t where 1=1 and t.id != 1;
    range:     EXPLAIN select * from t_test t where 1=1 and (t.id = 1 or t.id = 2);
    range:     EXPLAIN select * from t_test t where 1=1 and t.id BETWEEN 1 and 2;
    ALL:          EXPLAIN select * from t_test t where 1=1 and t.id like '%1';
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.id like '1%';
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.id like '%1%';
    const:     EXPLAIN select * from t_test t where 1=1 and t.id in (2);
    range:     EXPLAIN select * from t_test t where 1=1 and t.id not in (1);
    NULL:       EXPLAIN select * from t_test t where 1=1 and t.id is null;
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.id is not null;

    普通索引

    type   SQL

    ref: EXPLAIN select * from t_test t where 1=1 and t.type = 1; ALL: EXPLAIN select * from t_test t where 1=1 and t.type > 1; ALL: EXPLAIN select * from t_test t where 1=1 and t.type >= 1; ALL: EXPLAIN select * from t_test t where 1=1 and t.type < 1; ALL: EXPLAIN select * from t_test t where 1=1 and t.type <= 1; ALL: EXPLAIN select * from t_test t where 1=1 and t.type <> 1; ALL: EXPLAIN select * from t_test t where 1=1 and t.type != 1; ALL: EXPLAIN select * from t_test t where 1=1 and (t.type = 1 or t.type = 2); ALL: EXPLAIN select * from t_test t where 1=1 and t.type BETWEEN 1 and 2; ALL: EXPLAIN select * from t_test t where 1=1 and t.type like '%1'; ALL: EXPLAIN select * from t_test t where 1=1 and t.type like '1%'; ALL: EXPLAIN select * from t_test t where 1=1 and t.type like '%1%'; ref: EXPLAIN select * from t_test t where 1=1 and t.type in (2); ALL: EXPLAIN select * from t_test t where 1=1 and t.type not in (1); ref: EXPLAIN select * from t_test t where 1=1 and t.type is null; ALL: EXPLAIN select * from t_test t where 1=1 and t.type is not null;

     唯一索引

    
    
    type   SQL
    NULL:      EXPLAIN select * from t_test t where 1=1 and t.user_id = 1;
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.user_id > 1;
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.user_id >= 1;
    range:     EXPLAIN select * from t_test t where 1=1 and t.user_id < 1;
    range:     EXPLAIN select * from t_test t where 1=1 and t.user_id <= 1;
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.user_id <> 1;
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.user_id != 1;
    range:     EXPLAIN select * from t_test t where 1=1 and (t.user_id = 1 or t.user_id = 2);
    range:     EXPLAIN select * from t_test t where 1=1 and t.user_id BETWEEN 1 and 2;
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.user_id like '%1';
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.user_id like '1%';
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.user_id like '%1%';
    const:     EXPLAIN select * from t_test t where 1=1 and t.user_id in (2);
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.user_id not in (1);
    ref:       EXPLAIN select * from t_test t where 1=1 and t.user_id is null;
    ALL:       EXPLAIN select * from t_test t where 1=1 and t.id is not null;
  • 相关阅读:
    java语言实现堆排序
    堆排序
    静态分派
    谈mysql优化
    Unity2017.1官方UGUI文档翻译——Canvas
    Unity2017.1官方UGUI文档翻译——Rect Transform
    Unity2017.1官方UGUI文档翻译——Rich Text
    Unity2017.1官方UGUI文档翻译——Auto Layout
    Unity2017.1官方UGUI文档翻译——Animation Integration
    Unity2017.1官方UGUI文档翻译——Interaction Components
  • 原文地址:https://www.cnblogs.com/wrcold520/p/10728652.html
Copyright © 2020-2023  润新知