2 MySQL DML数据操纵语言 索引及执行计划

MySQL

1 SQL应用

1.1 DCL数据控制语言

DCL主要负责授权与撤权

grant 
revoke
1.2 DML数据操纵语言
1.2.1 insert

尽量批量插入,减少发起的事务。

1.2.2 update

建议:

  1. 将需要更新的数据的主键先查出来,然后按主键更新,这样做可以减少锁的征用,更加高效
  2. 如果无法达到以上需求,对于where条件后的列,需要设置合理索引
  3. 减少更新范围
  4. 尽量不要跨多表更新
1.2.3 delete

建议:

  1. 可以使用"伪删除",即增加一列表示是否删除,然后定期归档
  2. 批量删除,希望减少对业务的影响,推荐使用pt-archiver
  3. delete操作比较频繁,建议定期做碎片整理(innodb)
alter table t1 engine=innodb;

delete \ truncate \ drop 区别
表面区别:删除后主键是否重置。

delete 
逐行进行删除,删除时为数据打上delete标签,数据仍在磁盘中存在;

truncate  
删除时直接清空数据页,全部重置,删除速度快且彻底,很难回复;

drop 
删除时会清空数据页和表空间,也会清空表定义,删除更加彻底。
1.2.4 select

语句排序

select  select_list  from  where  group by  having  order by  limit 
where条件可使用
	比较操作符:= > < >= <= <> 
	逻辑连接符:and  or 
	模糊查询:like 
	其它:in  not in  beteween and 
		
group by + 聚合函数(sum, count, avg, max, min, group_concat)

5.7版本以后,SQL_MODE

SQL_MODE=only_full_group_by
  1. SQL_MODE 作用
    约束SQL行为,保证数据有意义。
mysql> select @@SQL_MODE;

+-----------------------------------------------------------------------------------------------------------------------+
| @@SQL_MODE                                    |
+-----------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+-----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
  1. only_full_group_by
    select后面的字段必须出现在group by后面,或者被聚合函数包裹,否则会报错。
    group by执行时会取出其后面的字段数据,进行排序,去重,再执行其它操作(聚合函数等)。
mysql> select countrycode, count(name), name from city group by countrycode;
ERROR 1055 (42000): Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'world.city.Name' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by 

解决方法,使用group_concat将各组内的指定字段数据转成一行显示。

mysql> select countrycode, count(name), group_concat(name) from city group by countrycode;
1.3 元数据获取

元数据一般指的是表的属性状态等。

mysql> use information_schema;
mysql> show tables;
+---------------------------------------+
| Tables_in_information_schema          |
+---------------------------------------+
| ADMINISTRABLE_ROLE_AUTHORIZATIONS     |
| APPLICABLE_ROLES                      |
| CHARACTER_SETS                        |
| CHECK_CONSTRAINTS                     |
| COLLATIONS                            |
| COLLATION_CHARACTER_SET_APPLICABILITY |
| COLUMNS                               |
| COLUMNS_EXTENSIONS                    |
| COLUMN_PRIVILEGES                     |
| COLUMN_STATISTICS                     |
| ENABLED_ROLES                         |
| ENGINES                               |
| EVENTS                                |
| FILES                                 |
| INNODB_BUFFER_PAGE                    |
| INNODB_BUFFER_PAGE_LRU                |
| INNODB_BUFFER_POOL_STATS              |
| INNODB_CACHED_INDEXES                 |
| INNODB_CMP                            |
| INNODB_CMPMEM                         |
| INNODB_CMPMEM_RESET                   |
| INNODB_CMP_PER_INDEX                  |
| INNODB_CMP_PER_INDEX_RESET            |
| INNODB_CMP_RESET                      |
| INNODB_COLUMNS                        |
| INNODB_DATAFILES                      |
| INNODB_FIELDS                         |
| INNODB_FOREIGN                        |
| INNODB_FOREIGN_COLS                   |
| INNODB_FT_BEING_DELETED               |
| INNODB_FT_CONFIG                      |
| INNODB_FT_DEFAULT_STOPWORD            |
| INNODB_FT_DELETED                     |
| INNODB_FT_INDEX_CACHE                 |
| INNODB_FT_INDEX_TABLE                 |
| INNODB_INDEXES                        |
| INNODB_METRICS                        |
| INNODB_SESSION_TEMP_TABLESPACES       |
| INNODB_TABLES                         |
| INNODB_TABLESPACES                    |
| INNODB_TABLESPACES_BRIEF              |
| INNODB_TABLESTATS                     |
| INNODB_TEMP_TABLE_INFO                |
| INNODB_TRX                            |
| INNODB_VIRTUAL                        |
| KEYWORDS                              |
| KEY_COLUMN_USAGE                      |
| OPTIMIZER_TRACE                       |
| PARAMETERS                            |
| PARTITIONS                            |
| PLUGINS                               |
| PROCESSLIST                           |
| PROFILING                             |
| REFERENTIAL_CONSTRAINTS               |
| RESOURCE_GROUPS                       |
| ROLE_COLUMN_GRANTS                    |
| ROLE_ROUTINE_GRANTS                   |
| ROLE_TABLE_GRANTS                     |
| ROUTINES                              |
| SCHEMATA                              |
| SCHEMA_PRIVILEGES                     |
| STATISTICS                            |
| ST_GEOMETRY_COLUMNS                   |
| ST_SPATIAL_REFERENCE_SYSTEMS          |
| ST_UNITS_OF_MEASURE                   |
| TABLES                                |
| TABLESPACES                           |
| TABLESPACES_EXTENSIONS                |
| TABLES_EXTENSIONS                     |
| TABLE_CONSTRAINTS                     |
| TABLE_CONSTRAINTS_EXTENSIONS          |
| TABLE_PRIVILEGES                      |
| TRIGGERS                              |
| USER_ATTRIBUTES                       |
| USER_PRIVILEGES                       |
| VIEWS                                 |
| VIEW_ROUTINE_USAGE                    |
| VIEW_TABLE_USAGE                      |
+---------------------------------------+
78 rows in set (0.00 sec)
1.3.1 统计业务数据库库名和表名

TABLES表保存了数据库中所有的表信息。

查看所有库及其下的所有表。

mysql> select table_schema, table_name from information_schema.tables;

查看业务库

mysql> select table_schema, table_name from information_schema.tables where table_schema not in ('mysql', 'sys', 'information_schema', 'performance_schema');

+--------------+-----------------+
| TABLE_SCHEMA | TABLE_NAME      |
+--------------+-----------------+
| test         | t100w           |
| world        | city            |
| world        | country         |
| world        | countrylanguage |
+--------------+-----------------+
4 rows in set (0.00 sec)
1.3.2 统计系统中所有非InnoDB表
mysql> select table_schema,table_name ,engine from information_schema.tables where table_schema not in ('mysql','sys','information_schema','performance_schema') and engine != 'innodb';
1.3.3 将所有非InnoDB表转换成InnoDB表
mysql> alter table world.t1 engine=innodb;

批量操作,将结果输出到/tmp/alter.sql
使用concat拼接SQL语句。

mysql> select concat("alter table ", table_schema, ".", table_name, " engine=innodb;") from information_schema.tables where table_schema not in ('mysql', 'sys', 'information_schema', 'performance_schema') and engine != 'innodb' into outfile '/tmp/alter.sql';

报错: 
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

解决方法,配置文件中将/tmp设定为安全路径。

cat /etc/my.cnf 
[mysqld]
user=mysql
basedir=/data/app/mysql
datadir=/data/3306/data
socket=/tmp/mysql.sock
secure-file-priv=/tmp
[mysql]
socket=/tmp/mysql.sock

修改后重启数据库

/etc/init.d/mysqld restart
cat /tmp/alter.sql
source /tmp/alter.sql
1.3.4 统计每个业务库的数据量

索引占用空间 + 数据占用空间

mysql> select table_schema, sum(INDEX_LENGTH+DATA_LENGTH)/1024 from information_schema.tables where table_schema not in ('mysql', 'sys', 'information_schema', 'performance_schema') group by table_schema;

+--------------+------------------------------------+
| TABLE_SCHEMA | sum(INDEX_LENGTH+DATA_LENGTH)/1024 |
+--------------+------------------------------------+
| world        |                           784.0000 |
| test         |                         48720.0000 |
+--------------+------------------------------------+
2 rows in set (0.01 sec)
1.3.5 数据字典信息统计

查看表的列信息。

mysql> select table_schema, table_name, group_concat(column_name) from information_schema.columns  where table_schema not in ('mysql', 'sys', 'informmation_schema', 'performance_schema') group by table_schema, table_name;

2 索引及执行计划

2.1 介绍

索引相当于一本书中的目录,可以加速查询。

MySQL中的索引类型

  1. Btree 平衡多叉树(btree\b+tree\b++tree),适合用于范围查找。
    Btree 平衡多叉树查找算法的本质是二分法。

  2. HASH 散列索引,适合用于等值查询。

  3. RTREE R树

  4. Fulltext 全文索引

2.2 Btree查找算法

Btree查找算法可以简单理解为是基于平衡多叉树理念的二分查找法。

2.2.1 Btree

将所有数据行均匀地存储于固定大小的存储区域中,即数据页(page),这些区域是树的叶子节点。
根据叶子节点生成中间节点,图中的方案是将叶子节点中的第一个数据(范围+指针)放入中间节点,即中间节点存储其下各个叶子节点的最小数据。
根据中间节点生成根节点,根节点存储其下各个中间节点的最小数据(范围+指针)。
B树的重点是平衡,即查找任何数据所需的时间复杂度相同,经历的步骤取决于树的层数。

2.2.2 B+tree

与B树相比,B+树在叶子节点中添加了双向指针,适合范围查找。
如果需要查找一定范围的值,可以向找到范围边界的叶子节点,再利用双向指针逐个找到所需的叶子节点。

在这里插入图片描述

2.2.3 B++tree

B++树(或B*树),是在B+树的基础上,在中间节点(分支节点)上添加双向指针。

2.3 索引介绍
2.3.1 索引分类
2.3.1.1 聚簇索引

聚簇索引,Clustered Index
extent 区、簇:连续的 64个 pages(16KB),默认大小为1MB(64*16KB)。
IOT表:索引组织表,就是按照聚簇索引将表中数据组织存储在多个区中。

生成前提:

  1. 如果建表时显式地设置了主键(PK),主键列为聚簇索引结构,组织存储数据。
  2. 如果没有主键,自动按照第一个不为空的UK(唯一键)作为聚簇索引,组织存储数据。
  3. 如果都不满足,会生成一个6字节的隐藏ROW_ID,作为聚簇索引,组织存储数据。

一般建议建表时,需要显式地设置主键。

生成节点过程
叶子节点:原表数据所在的数据页,就是聚簇索引的叶子节点
枝节点:存储下层叶子节点id的范围+指针
根节点:存储下层枝节点id的范围+指针

2.3.1.2 辅助索引

辅助索引是用于普通列的索引构建。

生成节点过程
叶子节点: 提取辅助索引列+ID主键值,根据辅助索引列排序,生成叶子节点。
枝节点:提取叶子结点辅助索引列值范围+指针
根节点:提取枝结点辅助索引列值范围+指针

按照辅助索引列条件查询时,首先扫描辅助索引树,得到ID值,然后回到聚簇索引扫描,中查找数据据行。
回表,回到聚簇索引查找的动作被称之为回表查询。

2.3.2 索引树高度

一般不建议超过4层。
索引树高度的影响因素

  1. 数据行太多,例如达到2000w+
    一般将索引树高度控制在3-4层。
    处理方案:分表、归档、分库分表
  2. 列值长度
    对于聚簇索引,一般使用自增的ID列作为索引,如果ID列的数据类型是BigInt,可以存储20位数字。
    对于辅助索引,列值长度可能各不相同。
    处理方案:前缀索引,只使用前15-20位数据作为索引的构建条件。
  3. 数据类型
    推荐使用可变长度的数据类型,例如对于char和varchar,推荐使用varchar。
    处理方案:选择简短的、合适的数据类型。
2.3.3 回表问题

回表产生的问题:IO次数、IO吞吐量、随机IO

减少回表

  1. 不回表
    如果需要查询的值都在辅助索引里有,就不需要回表了。
  2. 少量回表
    通过合适的联合索引,精细化查询条件。

使用数量级达到100万的数据进行压力测试,评估索引效果。

2.3.4 压力测试
mysql> select count(*) from t100w;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+

mysql> desc t100w;
+-------+-----------+------+-----+-------------------+-----------------------------------------------+
| Field | Type      | Null | Key | Default           | Extra      |
+-------+-----------+------+-----+-------------------+-----------------------------------------------+
| id    | int       | YES  |     | NULL              |      |
| num   | int       | YES  |     | NULL              |      |
| k1    | char(2)   | YES  |     | NULL              |      |
| k2    | char(4)   | YES  |     | NULL              |      |
| dt    | timestamp | NO   |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------------------------+

表没有建立任何索引。

提前压测

mysqlslap --defaults-file=/etc/my.cnf --concurrency=100 --iterations=1 --create-schema='test' --query="select * from test.t100w where k2='780P'" engine=innodb --number-of-queries=2000 -uroot -p123456 -verbose
--concurrency=100 模拟100名用户登录
--number-of-queries=2000 指定命令执行2000次
2.4 索引管理

查询索引

mysql> desc city;
mysql> show index from city;

创建索引

mysql> ALTER TABLE city ADD INDEX i_name(name)
mysql> ALTER TABLE city DROP INDEX i_name;

基础管理

# 创建前缀索引,name列前10个字符
mysql> ALTER TABLE city ADD INDEX i_name(name(10));

# 创建联合索引
mysql> ALTER TABLE city ADD INDEX ix(population, countrycode);

# 删除索引
mysql> ALTER TABLE city DROP INDEX i_name;

# 查看索引
mysql> show index from city;
2.5 执行计划
2.5.1 介绍

优化器会根据解析器获得的解析树,计算查询代价,做出评估并决定执行方案。
查看优化器生成的最终执行计划,有助于判断语句执行效率低,速度慢的原因,评估SQL执行会不会有问题。

2.5.2 操作
mysql> desc select * from test.t100w where k2='780P';
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | t100w | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 997335 |    10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
mysql> explain select * from test.t100w where k2='780P';
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | t100w | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 997335 |    10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
2.5.3 分析
table:语句操作的表
type:判断语句获取数据的方式,包括ALL、index、range、ref、eq_ref、const(system)
	ALL:全表扫描
	index:全索引扫描,主键列上的全索引扫描相当于全表扫描
	range:索引范围扫描,包括:> < >= <= like or in between and,例外情况:使用主键做不等值查询
	ref:辅助索引常量查询,即等值查询 = 
	eq_ref:多表连接中在非驱动表上的关联条件是主键或唯一键。
	const(system):主键或者唯一键的常量查询(等值查询)。

possible_keys:可能使用的索引
key:最终选择使用的索引 
rows:需要扫描的行数
Extra:额外信息,注意额外排序using filesort,order by、group by等会触发排序
2.6 联合索引应用细节
2.6.1 联合索引遵循“最左原则”
  1. 建立联合索引时,要选择重复值少的列放在最左侧;
    重复值少的列,选择度高。

  2. 查询条件中必须要包含最左列条件,才能使用联合索引。

2.6.2 辅助索引覆盖长度

全部覆盖
查询条件中只要包含最左列条件,无论其顺位,MySQL都会将其自动转化为最优的执行计划对应的排序。
尽量避免条件中间出现不等值查询。

idx(a, b, c );

select * from t1  where a=? and b=? and c=?
select * from t1  where b=? and a=? and c=?
select * from t1  where c=? and b=? and a=?
select * from t1  where c=? and a=? and b=?
select * from t1  where a=? and b=? and c>? 

部分覆盖

select * from t1  where a=? and b=?  
select * from t1  where a=? and c=?
select * from t1  where b=? and a=?  
select * from t1  where c=? and a=?  
select * from t1  where a=? and b>? and c=?
select * from t1  where a>? and b=? and c=?

不覆盖

select * from t1  where b=? and c=?

可以通过参数format=json,查看 "used_key_parts"来获取使用了哪些索引。

mysql> desc format=json select * from t100w where num=279106 and k1 >'dd' and k2='VWtu';
2.7 建立索引的原则(DBA运维规范)

(1) 必须要有主键,无关列
(2) 经常做为where条件列 order by group by join on, distinct 的条件(业务:产品功能+用户行为)
(3) 最好使用唯一值多的列作为索引,如果索引列重复值较多,可以考虑使用联合索引
(4) 列值长度较长的索引列,建议使用前缀索引.
(5) 降低索引条目,一方面不要创建没用索引,不常使用的索引清理,percona toolkit(xxxxx)
(6) 索引维护要避开业务繁忙期,建议用pt-osc
(7) 联合索引最左原则

2.8 不走索引的情况(开发规范)

(1) 没有查询条件,或者查询条件没有建立索引
(2) 查询结果集是原表中的大部分数据,应该是15-25%以上
(3) 索引本身失效,统计信息不真实(过旧)
现象:有一条select语句平常查询时很快,突然有一天很慢,会是什么原因

select  ---> 索引失效,统计数据不真实
innodb_index_stats  
innodb_table_stats  
mysql> ANALYZE TABLE world.city;

(4) 查询条件使用函数在索引列上,或者对索引列进行运算,运算包括(+,-,*,/,! 等)
例子:
错误的例子:select * from test where id-1=9;
正确的例子:select * from test where id=10;
算术运算
函数运算
子查询
(5) 隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误
(6) <> ,not in 不走索引(辅助索引)
(7) like “%_” 百分号在最前面不走

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值