查看本表的索引:
mysql:SHOW INDEX FROM 表名
oracle:SELECT * FROM USER_IND_COLUMNS WHERE TABLE_NAME = '表名'
索引优势:
查询
效率,降低数据库io操作成本。排序
成本,减轻cpu负荷btree叫做多路平衡搜索树,一颗m叉的btree树有如下特性:
个人主推方式二进行所有创建修改等操作
方式1: CREATE INDEX index_name ON table_name(column)
方式2: ALTER TABLE table_name ADD INDEX index_name(column)
方式1: CREATE INDEX composite_index_name ON table_name(col1, col2)
方式2: ALTER TABLE table_name ADD INDEX composite_index_name(col1, col2)
函数索引是MySql8.0支持的,之前版本不支持该函数索引
-- 创建函数索引
ALTER TABLE books ADD KEY idx_fun_data((DATE(created_time))) -- 注意函数需要用()包住,否则报错
ALTER TABLE books ADD KEY idx_fun_data((DATE(created_time)))-- 查看当前索引
mysql> SHOW INDEX FROM books;
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------------------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------------------------+
| books | 0 | PRIMARY | 1 | id | A | 2 | NULL | NULL | | BTREE | | | YES | NULL |
| books | 1 | idx_fun_data | 1 | NULL | A | 1 | NULL | NULL | YES | BTREE | | | YES | cast(`created_time` as date) |
| books | 1 | idx_fun_contact | 1 | NULL | A | 3 | NULL | NULL | YES | BTREE | | | YES | concat(`name`,`writer`) |
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------------------------+
explain查看是否使用索引
-- key = idx_fun_data 使用函数索引
mysql> EXPLAIN SELECT * FROM books WHERE DATE(created_time)='2000-1-1';
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | books | NULL | ref | idx_fun_data | idx_fun_data | 4 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+--------------+---------+-------+------+----------+-------+-- key = idx_fun_contact 使用函数索引
mysql> EXPLAIN SELECT CONCAT(name, writer) FROM books WHERE CONCAT(name, writer) = 'sssssss';
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | books | NULL | ref | idx_fun_contact | idx_fun_contact | 123 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
方式一DROP INDEX index_name ON table_name
方式二:ALTER TABLE table_name DROP INDEX index_name
SHOW INDEX FROM '表名'
SELECT * FROM USER_IND_COLUMNS WHERE TABLE_NAME = '表名'
适合创建索引
不适合创建索引
不适合建立索引
explain是模拟mysql查询优化器执行sql,可以看出mysql是如何优化执行你的sql语句。
explain有什么用?
- 读取表的顺序
- 数据读取操作的操作累心
- 哪些索引可以使用
- 哪些索引被实际使用
- 表之间的引用
- 每张表多少行被查询优化器查询
select_type属性 | 含义 |
---|---|
SIMPLE | 简单的select查询,不包含子查询和UNION |
PRIMARY | 查询中包含任何复杂的子查询部分,最外层标记为PRIMARY,最后执行 |
SUBQUERY | select或者where子句包含子查询 |
DERIVED | from列表中包含子查询(表连接)mysql会递归这些子查询,将子查询结果放在临时表中 |
UNION | 第二个select出现在union之后,标记为UNION(union包含在from子句中,外层select标记为DERIV-DR) |
UNION RESULT | 连接两个select语句的UNION |
图例为UNION RESULT
效率从好到差依次为:system > const > eq_ref > ref > range > index > ALL
查询中至少达到range
,最好可以达到ref
type属性 | 含义 |
---|---|
ALL | 全表扫描 |
INDEX | 读取索引,与ALL都是全表扫描,ALL读硬盘,INDEX读索引,降低了IO操作 |
RANGE | 只检索指定的行&#xff0c;where语句中的IN、between、<、>等范围查询 |
REF | 非唯一扫描&#xff0c;主表的关联约束可以匹配子表多行&#xff0c;一对多的情况 |
EQ_REF | 读取主表中和关联表&#xff0c;表中的每行组合成的一行 |
CONST | 通过索引一次找到&#xff0c;常见与主键约束(PRIMARY KEY) / 唯一约束(UNIQUE)&#xff0c;很快的将主键置于where列表中&#xff0c;mysql可以将该查询转化成一个常量 |
SYSTEM | 表记录只有一行&#xff08;是const的特例&#xff09; |
ALL:
INDEX:
RANGE:
REF&#xff1a;
EQ_REF:
CONST:
SYSTEM:
查询字段存在多个索引&#xff0c;将会被列出&#xff0c;但不一定会使用
实际使用到的索引&#xff0c;NULL表示没有用到索引&#xff0c;不为NULL则是实际使用到的索引
查询中若使用了覆盖索引&#xff0c;则改索引仅出现在key列表中
覆盖索引&#xff1a;SQL只需要通过索引就可以返回查询所需要的数据&#xff0c;而不必通过二级索引查到主键之后再去查询数据
如下所示&#xff0c;user_id
、id
建立了联合索引&#xff0c;所以查询结果会直接从索引中读取结果&#xff0c;而不需要全表扫描
显示的是最大可能长度&#xff0c;并非实际使用长度。
不损失精度的情况下&#xff0c;越小越好&#xff0c;速度越快
如果索引固定查询一个值的话显示的是const
&#xff0c;表示一个常量
如果使用了某个字段去匹配则显示&#xff0c;users.id表示被使用的字段&#xff0c;&#xff0c;null表示没有使用到索引去匹配行。
filtered表示的是&#xff1a;返回结果的行数占需读取行数的百分比
案例模拟隐试类型转化的索引搜索&#xff1a;
直接索引搜索
-- 走索引只查了一行&#xff0c;结果也是一行&#xff0c;所以filtered&#61;100%
mysql> explain select * from testt where name &#61; &#39;2000&#39;;
&#43;----&#43;-------------&#43;-------&#43;------------&#43;------&#43;---------------&#43;------------&#43;---------&#43;-------&#43;------&#43;----------&#43;-------------&#43;
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
&#43;----&#43;-------------&#43;-------&#43;------------&#43;------&#43;---------------&#43;------------&#43;---------&#43;-------&#43;------&#43;----------&#43;-------------&#43;
| 1 | SIMPLE | testt | NULL | ref | name_index | name_index | 33 | const | 1 | 100.00 | Using index |
&#43;----&#43;-------------&#43;-------&#43;------------&#43;------&#43;---------------&#43;------------&#43;---------&#43;-------&#43;------&#43;----------&#43;-------------&#43;
类型转化走where再走索引
-- 走索引查了两行&#xff0c;结果是一行&#xff0c;所以filtered&#61;50%
mysql> explain select * from testt where name &#61; 2000;
&#43;----&#43;-------------&#43;-------&#43;------------&#43;-------&#43;---------------&#43;------------&#43;---------&#43;------&#43;------&#43;----------&#43;--------------------------&#43;
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
&#43;----&#43;-------------&#43;-------&#43;------------&#43;-------&#43;---------------&#43;------------&#43;---------&#43;------&#43;------&#43;----------&#43;--------------------------&#43;
| 1 | SIMPLE | testt | NULL | index | name_index | name_index | 33 | NULL | 2 | 50.00 | Using where; Using index |
&#43;----&#43;-------------&#43;-------&#43;------------&#43;-------&#43;---------------&#43;------------&#43;---------&#43;------&#43;------&#43;----------&#43;--------------------------&#43;
where 1 &#61; 2
-- 索引按照 user_id,project_name,id 顺序建立
ALTER TABLE projects ADD INDEX user_id_index_test(user_id,project_name,id) COMMENT &#39;测试索引&#39;-- 查询也按照 user_id,project_name,id 顺序查询
SELECT * FROM projects WHERE user_id &#61; 18 AND project_name &#61; &#39;zhangsan&#39; AND id &#61; 1-- 最左匹配原则&#xff0c;不用 user_id 开头&#xff0c;用不上索引
SELECT * FROM projects WHERE project_name &#61; &#39;zhangsan&#39; AND id &#61; 1
-- 使用范围后的列索引失效
SELECT * FROM projects WHERE user_id > 18 AND project_name &#61; &#39;zhangsan&#39; AND id &#61; 1
-- 如上 user_id 使用range查找后&#xff0c;project_name、id无法使用全职匹配查找&#xff0c;&#xff0c;&#xff0c;此时联合索引只用上了user_id的范围查找。
少用select *
&#xff08;只访问索引列&#xff0c;索引列和查询列一致&#xff09;
要什么取什么&#xff0c;不要使用*取出所有的值
<>
、!&#61;
无法使用索引
is null
、is not null
无法使用索引
like
开头的 ‘%admin’ 索引失效
解决办法&#xff1a;使用覆盖索引
-- select字段必须是索引字段
select name from projects where name like &#39;%hhhh%&#39;
-- project_name是字符串类型&#xff0c;使用20000会隐试转化类型为字符串
EXPLAIN SELECT * FROM projects WHERE project_name &#61; 20000
类型不一致&#xff0c;隐试转换的情况&#xff0c;不走索引
按照字段原类型查询&#xff0c;走索引
or
&#xff0c;不走索引