18.2.索引ICP

0. 文章内容

凡是创建的普通的索引默认是会跟主键做一个联合索引

idx_col(col) => idx_col(col, id)

1. 索引(索引是什么,怎么创建(σ゚∀゚)σ..自个百度)
   1.1 索引的类型
       1.1.1 根据创建分类
             1.1.1.1 主键索引(聚集索引 & 特殊索引)
             1.1.1.2 二级索引(非聚集索引)
       1.1.2 根据使用分类
             1.1.2.1 覆盖索引
             1.1.2.2 辅助索引(二级索引+回表 30%(需要获取的数据) )
       1.1.1 根据字段数量分类
             1.1.3.1 单索引(唯一索引 -- 几乎为唯一值的字段 90%以上是惟一的)
             1.1.3.2 联合索引(复合索引 - 推荐创建联合索引)
   1.2 索引结构(BTree)
       1.2.1 BTree (根据平衡二叉树进行演变 索引维护成本 会随索引的长度增加)

       主键:数据类型最好自增,字符串主键

   1.3 最左匹配原则(联合索引)
       1.3.1 规则是什么?
       1.3.2 演示
       1.3.3 覆盖索引就是任选(・ω<)☆
   1.4 关于SQL语句优化的点思路
       1.4.1 过滤性SQL
             1.4.1.1 单SQL
             1.4.1.2 join
       1.4.2 本质上是全表扫描的SQL
             1.4.2.1 单SQL
             1.4.2.2 join
   1.5 索引的疑问与注意
       1.5.1 索引的复用性(=゜ω゜)ノ
       1.5.2 索引建立限制(数量,字段数量)
2. 优化器执行流程
3. 学员案例实践
4. max与min的一个优化技巧(利用索引排序)
5. 索引的总结

3. 查询优化器的操作

mysql> select * from information_schema.OPTIMIZER_TRACE \G;
*************************** 1. row ***************************
QUERY: explain select * from details where equipmentMD5 = "4" and type = 4 and age = 0
TRACE: {
  "steps": [
    {
      "join_preparation": {
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `details`.`id` AS `id`,`details`.`equipmentMD5` AS `equipmentMD5`,`details`.`type` AS `type`,`details`.`age` AS `age` from `details` where ((`details`.`equipmentMD5` = '4') and (`details`.`type` = 4) and (`details`.`age` = 0))"
          }
        ]
      }
    },
    {
      "join_optimization": {
        "select#": 1,
        "steps": [
          {
            "condition_processing": {
              "condition": "WHERE",
              "original_condition": "((`details`.`equipmentMD5` = '4') and (`details`.`type` = 4) and (`details`.`age` = 0))",
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "((`details`.`equipmentMD5` = '4') and multiple equal(4, `details`.`type`) and multiple equal(0, `details`.`age`))"
                },
                {
                  "transformation": "constant_propagation",
                  "resulting_condition": "((`details`.`equipmentMD5` = '4') and multiple equal(4, `details`.`type`) and multiple equal(0, `details`.`age`))"
                },
                {
                  "transformation": "trivial_condition_removal",
                  "resulting_condition": "((`details`.`equipmentMD5` = '4') and multiple equal(4, `details`.`type`) and multiple equal(0, `details`.`age`))"
                }
              ]
            }
          },
          {
            "substitute_generated_columns": {
            }
          },
          {
            "table_dependencies": [
              {
                "table": "`details`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ]
              }
            ]
          },
          {
            "ref_optimizer_key_uses": [
              {
                "table": "`details`",
                "field": "type",
                "equals": "4",
                "null_rejecting": false
              },
              {
                "table": "`details`",
                "field": "age",
                "equals": "0",
                "null_rejecting": false
              },
              {
                "table": "`details`",
                "field": "type",
                "equals": "4",
                "null_rejecting": false
              },
              {
                "table": "`details`",
                "field": "equipmentMD5",
                "equals": "'4'",
                "null_rejecting": false
              }
            ]
          },
          {
            "rows_estimation": [
              {
                "table": "`details`",
                "range_analysis": {
                  "table_scan": {
                    "rows": 100042,
                    "cost": 20300
                  },
                  "potential_range_indexes": [
                    {
                      "index": "PRIMARY",
                      "usable": false,
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_type",
                      "usable": true,
                      "key_parts": [
                        "type",
                        "id"
                      ]
                    },
                    {
                      "index": "idx_age_type_equipmentMD5",
                      "usable": true,
                      "key_parts": [
                        "age",
                        "type",
                        "equipmentMD5",
                        "id"
                      ]
                    }
                  ],
                  "best_covering_index_scan": {
                    "index": "idx_age_type_equipmentMD5",
                    "cost": 21276,
                    "chosen": false,
                    "cause": "cost"
                  },
                  "setup_range_conditions": [
                  ],
                  "group_index_range": {
                    "chosen": false,
                    "cause": "not_group_by_or_distinct"
                  },
                  "analyzing_range_alternatives": {
                    "range_scan_alternatives": [
                      {
                        "index": "idx_type",
                        "ranges": [
                          "4 <= type <= 4"
                        ],
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": true,
                        "using_mrr": false,
                        "index_only": false,
                        "rows": 50021,
                        "cost": 60026,
                        "chosen": false,
                        "cause": "cost"
                      },
                      {
                        "index": "idx_age_type_equipmentMD5",
                        "ranges": [
                          "0 <= age <= 0 AND 4 <= type <= 4 AND 4 <= equipmentMD5 <= 4"
                        ],
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": true,
                        "using_mrr": false,
                        "index_only": true,
                        "rows": 1,
                        "cost": 1.21,
                        "chosen": true
                      }
                    ],
                    "analyzing_roworder_intersect": {
                      "intersecting_indexes": [
                        {
                          "index": "idx_age_type_equipmentMD5",
                          "index_scan_cost": 1,
                          "cumulated_index_scan_cost": 1,
                          "disk_sweep_cost": 0,
                          "cumulated_total_cost": 1,
                          "usable": true,
                          "matching_rows_now": 1,
                          "isect_covering_with_this_index": true,
                          "chosen": true
                        }
                      ],
                      "clustered_pk": {
                        "clustered_pk_added_to_intersect": false,
                        "cause": "no_clustered_pk_index"
                      },
                      "chosen": false,
                      "cause": "too_few_indexes_to_merge"
                    }
                  },
                  "chosen_range_access_summary": {
                    "range_access_plan": {
                      "type": "range_scan",
                      "index": "idx_age_type_equipmentMD5",
                      "rows": 1,
                      "ranges": [
                        "0 <= age <= 0 AND 4 <= type <= 4 AND 4 <= equipmentMD5 <= 4"
                      ]
                    },
                    "rows_for_plan": 1,
                    "cost_for_plan": 1.21,
                    "chosen": true
                  }
                }
              }
            ]
          },
          {
            "considered_execution_plans": [
              {
                "plan_prefix": [
                ],
                "table": "`details`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "access_type": "ref",
                      "index": "idx_type",
                      "rows": 50021,
                      "cost": 10871,
                      "chosen": true
                    },
                    {
                      "access_type": "ref",
                      "index": "idx_age_type_equipmentMD5",
                      "rows": 1,
                      "cost": 1.2,
                      "chosen": true
                    },
                    {
                      "access_type": "range",
                      "range_details": {
                        "used_index": "idx_age_type_equipmentMD5"
                      },
                      "chosen": false,
                      "cause": "heuristic_index_cheaper"
                    }
                  ]
                },
                "condition_filtering_pct": 100,
                "rows_for_plan": 1,
                "cost_for_plan": 1.2,
                "chosen": true
              }
            ]
          },
          {
            "attaching_conditions_to_tables": {
              "original_condition": "((`details`.`age` = 0) and (`details`.`type` = 4) and (`details`.`equipmentMD5` = '4'))",
              "attached_conditions_computation": [
              ],
              "attached_conditions_summary": [
                {
                  "table": "`details`",
                  "attached": null
                }
              ]
            }
          },
          {
            "refine_plan": [
              {
                "table": "`details`"
              }
            ]
          }
        ]
      }
    },
    {
      "join_explain": {
        "select#": 1,
        "steps": [
        ]
      }
    }
  ]
}

3… join在这里插入图片描述

在这里插入图片描述

4. max与min的一个优化技巧(利用索引排序)

这里以salary为例

select * from details limit 0,5;
+----+--------------------+------+-----+
| id | equipmentMD5       | type | age |
+----+--------------------+------+-----+
|  1 | wQU5bJjXuJsJF1CVEE |    1 | 101 |
|  2 | pp5nK4nsU2RJxY5FHb |    1 |  98 |
|  3 | fI7au1b9Mm9zKK2lQX |    1 |   6 |
|  4 | IKvi21q3wX0x6kRXGj |    1 |  37 |
|  5 | JI3ybbKuyzNIm9HYjN |    1 |   3 |
+----+--------------------+------+-----+
5 rows in set (0.00 sec)

如上的数据是最初始的状态,也就是没有进行操作的时候

show index from details;
+---------+------------+--------------+--------------+-------------+-----------+-------------+------------+
| Table   | Non_unique | Key_name     | Seq_in_index | Column_name | Collation | Cardinality | Index_type |
+---------+------------+--------------+--------------+-------------+-----------+-------------+------------+
| details |          0 | PRIMARY      |            1 | id          | A         |      997442 | BTREE      |
| details |          1 | idx_age_type |            1 | age         | A         |         121 | BTREE      |
| details |          1 | idx_age_type |            2 | type        | A         |         545 | BTREE      |
| details |          1 | idx_type     |            1 | type        | A         |           3 | BTREE      |
+---------+------------+--------------+--------------+-------------+-----------+-------------+------------+
4 rows in set (0.00 sec)

现在我们想要知道age最低和最大的用户

select id,max(age) from details;
+----+----------+
| id | max(age) |
+----+----------+
| 55 |      119 |
+----+----------+
1 row in set (0.18 sec)

select * from details where id = 55;
+----+--------------------+------+-----+
| id | equipmentMD5       | type | age |
+----+--------------------+------+-----+
| 55 | zwWzo4qtjdEffbMguZ |    1 |   0 |
+----+--------------------+------+-----+
1 row in set (0.00 sec)

select id,age from details where age = (select max(age) from details) limit 0, 1;
+----+-----+
| id | age |
+----+-----+
| 67 | 119 |
+----+-----+
1 row in set (0.00 sec)

-- 数据量太多....

select id,age from details order by age desc limit 0, 1;
+--------+-----+
| id     | age |
+--------+-----+
| 999901 | 119 |
+--------+-----+
1 row in set (0.00 sec)

可以看到我们就需要使用第三条SQL的方式,不过我们也可以通过order by排序;不过我们也可以通过使用索引快速获取所需要的数据;比如这里我们使用age索引获取最大和最小

最小

select id,age from details use index(idx_age_type) limit 0,1;
+----+-----+
| id | age |
+----+-----+
| 55 |   0 |
+----+-----+
1 row in set (0.00 sec)

最大

select count(*) from details;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.13 sec)

select id,age from details use index(idx_age_type) limit 999999,1;
+--------+-----+
| id     | age |
+--------+-----+
| 999901 | 119 |
+--------+-----+
1 row in set (0.16 sec)

这个策略的话可以了解一下,在一些情况下是会让MySQL扫描尽可能少的记录数。不过这种方式实际上并不是SQL的本意了,但是它也会返回我们所需要的数据信息,之所以可以这么做是因为与income索引本质在建立的时候就会对于数据的结果进行了排序

5. 索引总结

在联合索引中:SQL索引联合索引的话通常来说最好是不要超过5个,因为超过了五个在过滤上就没有太大的效果,但是如果说有些时候需要定义10个字段的关联能起到很好地效果的话还是可以去这么做的。如果在目前的SQL中我们不想建立5个索引的话,那么我们可以尝试去优化子查询来提高MySQL的查询效率

在使用索引的同时,还应该了解MySQL中索引存在的限制,以便在索引应用中尽可能地避开限制所带来的问题。下面列出了目前MySQL中与索引使用相关的 限制

  1. blob和text类型的列只能创建前缀索引
  2. MySQL 5.7 对于普通索引不支持函数操作,若要使用可以定义函数索引
  3. 使用不等于(!=或者 <>)的时候MySQL无法使用索引;
  4. 使用like操作的时候如果 %在前面无法使用索引
  5. hash索引不能做范围查询

如下内容出自上期优化课程中的笔记

10.4、什么情况使用索引
当使用不以通配符开始的like
Select * from table1 where username like 'pack%';
一个索引字段的前缀使用了order by或者group by;
Select * from table2 order by field1;
对索引字段使用了>,=,<,>=,<=,IS NULLBETWEEN
Select * from table3 where total_fee IS NULL
查找某个字段的最大值和最小值
Select min(score),max(score) from table4 where class_id = 1;
查询的列是后面字段的部分时间
Select time1 from table5 where time2 = '2017-2';

10.5、什么情况不使用索引

以通配符开始的like查询
Select * from table1 where username like '%pack%';

搜索某列,而在另一个列的索引做order by会优先选择与where上的条件
explain select * from customers where mobile = "0" order by city;
+----+-------------+-----------+------+---------------+------------+---------+-------+--------+----------+---------------------------------------+
| id | select_type | table     | type | possible_keys | key        | key_len | ref   | rows   | filtered | Extra                                 |
+----+-------------+-----------+------+---------------+------------+---------+-------+--------+----------+---------------------------------------+
|  1 | SIMPLE      | customers | ref  | idx_mobile    | idx_mobile | 33      | const | 245076 |   100.00 | Using index condition; Using filesort |
+----+-------------+-----------+------+---------------+------------+---------+-------+--------+----------+---------------------------------------+
1 row in set, 1 warning (0.00 sec)


10.6、误区
不是在where条件常用的列都加上索引
Where course = 'php' and number > 50;
在多列建立索引后,查询哪个列,都将发挥作用?
满足左前缀要求。
Index(field1,field2,field3)
Where  field1 = 1						                              生效
Where  field1 = 1 and field2 =2		                        生效
Where  field1 = 1 and field2 =2 and field3 = 3;	          生效
Where  field2 = 2 Where field3 =3                         不生效
Where  field1 = 1 and field3 = 3;	                        field1生效,field3不生效
Where  field1 = 1 and field2 >2 and field3 = 3;	          field1和field2生效,field3不生效
Where  field1 = 1 and field2 like 'pack%' and field3 = 3; field1和field2生效,field3不生效
explain select * from customers1 where gender > 0 ;
+----+-------------+------------+------------+------+--------------------------------------------+------+--------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys                              | key  | rows   | filtered | Extra       |
+----+-------------+------------+------------+------+--------------------------------------------+------+--------+----------+-------------+
|  1 | SIMPLE      | customers1 | NULL       | ALL  | idx_gender_city_name_monthsalary_yearbonus | NULL | 577859 |    50.00 | Using where |
+----+-------------+------------+------------+------+--------------------------------------------+------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

最左前缀:
选择一个能够淘汰最多纪录的索引;
字段是有序的;

10.7SQL的优化
Limit分页优化
Select * from table1 order by id asc limit 2200,10;
Select * from table1 where id>=2200 order by id limit 10;

Count(*)   改为辅助索引
Select count(*) from table2;
Select count(*) from table2 where course_id >=0;
聚集索引:主键、没有主键则定位第一个唯一索引(所有行的值非空)、如果上2个条件都不满足则自动产生一个6字节的id聚集索引。
辅助索引:包含键值的书签,会存储书签数据。

Not in子查询优化
select * from customers where id in (select id from salary ); 时间: 9.841s
select * from customers where exists (select id from salary where customers.id = salary.id );时间: 3.780s
select * from customers left join salary on customers.id = salary.id 时间: 2.072s

Or条件优化
Select *  from table1 where a = '123' or b = '456';
Select *  from table1 where a = '123' union all Select *  from table1  b = '456';
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值