1.主键索引
2.普通索引
* 联合索引
* 前缀索引
3.唯一索引
explain 分析执行效率(优化SQL语句)
1.全表扫描
select * from tb1;
mysql> explain select * from world.city;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | city | ALL | NULL | NULL | NULL | NULL | 4188 | NULL |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
2.索引扫描
* index:全索引扫描
mysql> explain select CountryCode from world.city;
* range:范围查询
mysql> explain select * from world.city where population > 30000000;
* ref:使用非唯一索引扫描或者唯一索引的前缀扫描,返回匹配某个单独值的记录行。
mysql> explain select * from world.city where countrycode='USA' union all select * from world.city where countrycode='CHN';
* eq_ref:连表查询(内连接),并且等价条件是主键或者唯一键
join B
on A.sid=B.sid
* **const、system**:当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。
mysql> explain select * from world.city where id=1;
* null:查询的值,不在范围内(根本不工作)
explain select * from world.city where population > 3000000000000000000000000000000000000000000000;
Extra(扩展) Using temporary Using filesort 使用了默认的文件排序(如果使用了索引,会避免这类排序)
mysql> explain select * from city where countrycode='CHN' order by population;
解决方案
mysql> explain select * from city where population>30000000 order by population;
Using join buffer
注意:
* * *
row:越小越好
key_len:越小越好
使用前缀索引,控制key_len
索引建立的规范(原则)
1.唯一索引
select count(*) from world.city;
select count(distinct(countrycode)) from world.city;
select count(distinct(countrycode,population)) from world.city;
2.联合索引
3.为经常需要排序、分组和联合操作的字段建立索引
4.为常作为查询条件的字段建立索引
* 唯一索引
* 联合索引
* 普通索引
5.尽量使用前缀索引
6.限制索引的数目 索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。 修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新
7.删除不再使用或者很少使用的索引 表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理 员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。
走索引和不走索引的情况
1.全表扫描(不执行)
mysql> explain select * from world.city;
2.查询结果集是原表中的大部分数据,应该是25%以上
mysql> explain select * from world.city where population > 3000000;
mysql> explain select * from world.city where population > 300 limit 10;
3.索引本身失效,或者损坏
删除索引,重建索引
4.使用列名,进行条件运算
mysql> explain select * from world.city where id-1=9;
5.隐式转换,不走索引
mysql> create table suibian(id int,QQ varchar(11));
mysql> insert into suibian values(1,'100'),(2,'110'),(3,120);
mysql> alter table suibian add index idx_qq(qq);
mysql> explain select * from suibian where qq='120';
+----+-------------+---------+------+---------------+--------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+--------+---------+-------+------+-----------------------+
| 1 | SIMPLE | suibian | ref | idx_qq | idx_qq | 36 | const | 1 | Using index condition |
+----+-------------+---------+------+---------------+--------+---------+-------+------+-----------------------+
mysql> explain select * from suibian where qq=120;
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | suibian | ALL | idx_qq | NULL | NULL | NULL | 3 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
6.模糊查询like %在最前面的时候,不管结果集是多少
mysql> explain select * from world.city where countrycode like '%HN';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | city | ALL | NULL | NULL | NULL | NULL | 4188 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
建议,不使用MySQL,而是使用elasticsearch
7.<> 、 not in不走索引
mysql> explain select * from world.city where population <> 102361;
union all
limit
8.联合索引,单独引用联合索引里非第一位置的索引列
按照创建索引的顺序,查询数据
MySQL存储引擎-innodb
img查看存储引擎
mysql> show engines;
查看整个数据库中,哪些表是innodb
mysql> select table_schema,table_name,engine from information_schema.tables where engine='innodb';
查看整个数据库中,哪些表是myisam
mysql> select table_schema,table_name,engine from information_schema.tables where engine='myisam';
innodb和myisam的物理区别
#myisam
[root@db01 mysql]# ll user.*
-rw-rw---- 1 mysql mysql 10684 11月 28 14:43 user.frm #表结构
-rw-rw---- 1 mysql mysql 1408 12月 2 08:48 user.MYD #表空间
-rw-rw---- 1 mysql mysql 2048 12月 2 08:48 user.MYI
#innodb
[root@db01 zls]# ll
-rw-rw---- 1 mysql mysql 8556 12月 4 11:02 zls1.frm #表结构
-rw-rw---- 1 mysql mysql 98304 12月 4 11:02 zls1.ibd #表空间
核心特性
* MVCC 多版本并发控制
* 事务
* 行级锁
* 热备
* CSR(自动故障恢复)
myisam
查看当前使用的存储引擎
mysql> SELECT @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| InnoDB |
+--------------------------+
mysql> show create table zls.zls1;
修改配置文件
default-storage-engine=<Storage Engine>
企业案例
**项目背景:**
公司原有的架构:一个展示型的网站,LAMT,MySQL5.1.77版本(MYISAM),50M数据量。
**小问题不断:**
* 1、表级锁:对表中任意一行数据修改类操作时,整个表都会锁定,对其他行的操作都不能同时进行。
* 2、不支持故障自动恢复(CSR):当断电时有可能会出现数据损坏或丢失的问题。
如何解决????
1.准备新环境,使用mysql5.6.44
./mysql_install_db --user=mysql --basedir=/application/mysql --datadir=/application/mysql/data
</pre>
2.备份导出数据
mysqldump -B 程序库> /tmp/full.sql
</pre>
3.修改存储引擎
sed -i 's#MyISAM#InnoDB#g' /tmp/full.sql
vim /tmp/full.sql
:%s#MyISAM#InnoDB#g
</pre>
4.将备份的数据导入新环境
mysql < /tmp/full.sql
</pre>
5.修改代码,连接数据库的IP
6.先停库
7.截取全备,到停库之间的新数据
8.恢复到新数据库,开启业务
innodb-表空间
1.共享表空间(5.5版本以后出现共享表空间概念)
* 系统数据
* 临时表
* undo log(事务日志)
2.独立表空间
* 生产数据,用户数据
#共享表空间(默认大小12M)
[root@db01 data]# ll
-rw-rw---- 1 mysql mysql 79691776 12月 4 11:35 ibdata1
mysql> show variables like '%path%';
+-----------------------+------------------------+
| Variable_name | Value |
+-----------------------+------------------------+
| innodb_data_file_path | ibdata1:12M:autoextend |
| ssl_capath | |
| ssl_crlpath | |
+-----------------------+------------------------+
[root@db01 data]# du -sh ibdata1
76M ibdata1
共享表空间切割
[root@db01 data]# vim /etc/my.cnf
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend
重启数据库
[root@db01 data]# /etc/init.d/mysqld restart
报错原因:设置共享表空间的大小,50M小于实际表空间大小76M
解决方法:修改配置文件中的50M,76M
innodb_data_file_path=ibdata1:76M;ibdata2:50M:autoextend
注意:ibdata1 已产生的共享表空间大小一定要与配置文件中的大小一致,不能多,也不能少
开启独立表空间
mysql> show variables like '%per_table%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_file_per_table | ON |
+-----------------------+-------+
企业案例
在没有备份数据的情况下,突然断电导致表损坏,打不开数据库。
解决思路:
1.准备新环境
2.将旧数据导入到新环境
3.需要知道建表语句(表结构)
管开发要建表语句
CREATE TABLE `city_new` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` char(35) NOT NULL DEFAULT '',
`CountryCode` char(3) NOT NULL DEFAULT '',
`District` char(20) NOT NULL DEFAULT '',
`Population` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`),
KEY `CountryCode` (`CountryCode`),
KEY `idx_pop` (`Population`)
) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1;
#删除新表的表空间
mysql> alter table world.city_new discard tablespace;
#拷贝旧表空间
[root@db02 world]# cp -a city.ibd city_new.ibd
#导入表空间
mysql> alter table world.city_new import tablespace;
mysql> select * from world.city_new;
#删除旧表
[root@db02 world]# rm -fr city.ibd city.frm
#新表改名
mysql> alter table world.city_new rename world.city;
网友评论