———————————————————创建表结构————————————————————-
    CREATE TABLE tb_sku (
    id int(11) NOT NULL,
    sn varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    name varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    price decimal(10, 2) NULL DEFAULT NULL,
    num int(11) NULL DEFAULT NULL,
    alter_num int(11) NULL DEFAULT NULL,
    image varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    images varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    weight double NULL DEFAULT NULL,
    create_time varchar(30) NULL DEFAULT NULL,
    update_time varchar(30) NULL DEFAULT NULL,
    category_name varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    brand_name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    spec varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    sale_num int(11) NULL DEFAULT NULL,
    comment_num int(11) NULL DEFAULT NULL,
    status char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    PRIMARY KEY (id) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

    导入1000w数据(由于1000w的数据量较大 , 如果直接加载1000w , 会非常耗费CPU及内存 ; 已经拆分为5个部分 , 每一个部分为200w数据 , load 5次即可 ;
    windows:
    load data local infile ‘C:\Users\Allen\Desktop\tb_sku1.sql’ into table tb_sku fields terminated by ‘,’lines terminated by ‘\n’;

    如果报Permission denied:secure-file-priv=”/“
    Linux:
    load data local infile ‘/root/sql/tb_sku1.sql’ into table tb_sku fields terminated by ‘,’ lines terminated by ‘\n’;

    ⚫ 验证索引效率
    在未建立索引之前,执行如下SQL语句,查看SQL的耗时。
    SELECT FROM tb_sku WHERE sn=’1000000003145001’
    ⚫针对字段创建索引
    create index idx_sku_sn on tb_sku(sn);
    ⚫然后再次执行相同的SQL语句,再次查看SQL的耗时。
    SELECT
    FROM tb_sku WHERE sn=’1000000003145001’

    (1) 最左前缀法则
    如果索引了多列(联合索引),要遵守最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。
    如果跳跃某一列,索引将部分失效(后面的字段索引失效)。
    (1)EXPLAIN SELECT FROM tb_user WHERE profession =’软件工程师’ and age=’31’ and status=’0’;
    (2)EXPLAIN SELECT
    FROM tb_user WHERE profession =’软件工程师’ and age=’31’ ;
    (3)EXPLAIN SELECT FROM tb_user WHERE profession =’软件工程师’ ;
    (4)EXPLAIN SELECT
    FROM tb_user WHERE age=’31’ and status=’0’;
    (5)EXPLAIN SELECT * FROM tb_user WHERE status=’0’;

    思考:下面的sql语句索引会不会失效?
    (1)EXPLAIN SELECT * FROM tb_user WHERE age=’31’ and status=’0’ and profession =’软件工程师’;

    (2)范围查询
    联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效
    EXPLAIN SELECT FROM tb_user WHERE profession =’软件工程师’ and age>’30’ and status=’0’;
    EXPLAIN SELECT
    FROM tb_user WHERE profession =’软件工程师’ and age>=’31’ and status=’0’;

    (3)索引列运算
    不要在索引列上进行运算操作, 索引将失效
    explain select * from tb_user where substring(phone,10,2) =’15’;

    (4) 字符串不加引号
    字符串类型字段使用时,不加引号, 索引将失效。
    EXPLAIN SELECT FROM tb_user WHERE profession =’软件工程师’ and age=30 and status=0;
    EXPLAIN SELECT
    FROM tb_user WHERE phone=17267171393;

    (5) 模糊查询
    如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。
    explain select from tb_user where profession like ‘软件%’;
    explain select
    from tb_user where profession like ‘%工程’;
    explain select * from tb_user where profession like ‘%工%’;

    (6) or连接的条件
    用or分割开的条件, 如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。
    explain select from tb_user where id =10 or age =30;
    explain select
    from tb_user where phone =’17267171393’ or age =30;
    由于age没有索引,所以即使id、phone有索引,索引也会失效。所以需要针对于age也要建立索引。

    (7)数据分布影响
    如果MySQL评估使用索引比全表更慢,则不使用索引。
    explain select from tb_user where phone >=’17799990020’;
    explain select
    from tb_user where phone >=’17799990000’;
    explain select from tb_user where phone >=’17799990010’;
    explain select
    from tb_user where phone >=’17799990015’;
    (8)SQL提示
    SQL提示,是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。
    为profession创建单列索引:create index idx_user_pro on tb_user(profession);

    思考:
    根据最左前缀法则会用到联合索引,单列索引也满足条件,那么到底会走那个索引呢?
    explain select * from tb_user where profession =’软件工程师’

    use index:告诉数据库哪个索引
    explain select * from tb_user use index(idx_user_pro) where profession =’软件工程师’

    ignore index:告诉数据库不用哪个索引
    explain select * from tb_user ignore index(idx_user_pro) where profession =’软件工程师’

    force index:告诉数据库必须用哪个索引
    explain select * from tb_user force index(idx_user_pro) where profession =’软件工程师’

    (9)覆盖索引
    尽量使用覆盖索引,减少SELECT *:查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到。

    创建了比较多的索引,删除多余索引:
    drop index idx_email on tb_user; drop index idx_user_pro on tb_user;

    explain select id,profession from tb_user where profession =’软件工程师’ and age =31 and status =’0’;

    explain select id,profession,age from tb_user where profession =’软件工程师’ and age =31 and status =’0’;

    explain select id,profession,age,status from tb_user where profession =’软件工程师’ and age =31 and status =’0’;
    ——————————————————————————-
    explain select id,profession,age,status,name from tb_user where profession =’软件工程师’ and age =31 and status =’0’;

    mysql的版本不一样,Extra展示的信息不一样。以下是8.0以上的版本
    image.png

    注意:
    using index condition :查找使用了索引,但是需要回表查询数据
    using where; using index :查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据

    image.png

    image.png

    思考:
    一张表, 有四个字段(id, username, password, status), 由于数据量大, 需要对以下SQL语句进行优化, 该如何进行才是最优方案:
    select id, username, password, status from tb_user where username=’admin’;

    1、前缀索引:
    当字段类型为字符串(varchar,text等)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘IO, 影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。
    ➢ 语法:CREATE INDEX idx_xxx ON 表名(column(n)),n代表这个字段的前n个字符作为索引
    ➢ 前缀长度
    可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高 , 唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。
    例如:
    select count(email) from tb_user/count() from tb_user;
    select count(distinct email) from tb_user/count(
    ) from tb_user;

    我们借助两个公式:
    select count(distinct email)/count(
    ) from tb_user;
    select count(distinct substring(email,1,5)/count(*) from tb_user;
    — 前五个区分度比较高了

    前缀索引的查找流程:

    image.png
    2、单列索引与联合索引
    单列索引:即一个索引只包含单个列。
    联合索引:即一个索引包含了多个列。
    在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,而非单列索引。

    单列索引情况:
    explain select id, phone ,name from tb_user where phone =’1779990010’ and name =’韩信’
    image.png

    多条件联合查询时,MySQL优化器会评估哪个字段的索引效率更高,会选择该索引完成本次查询。