1.创建表时,指定存储引擎
注意存储引擎是以表为单位的
CREATE TABLE table_name (
字段1 字段1类型
....
)ENGINE = INNODB;
不指定 ENGINE = INNODB,mysql5.5版本以上默认就是INNODB
2.查看当前数据库支持哪些存储引擎
show engines;
InnoDB是一种兼顾高可靠性和高性能的通用存储引擎,在MySQL 5.5 之后是默认存储引擎
特点
文件
xxx.idb: xxx代表的是表名,innoDB引擎的每张表都会对应这样的一个表空间文件,存储该表的表结构(frm、sdi)、数据和索引。
可以在存放表空间文件的目录下打开cmd,然后运行 ibd2sdi xxxx.idb,就可以查看这个表空间文件的sdi数据
MYISAM | INNODB | |
---|---|---|
事务支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表空间大小 | 较小 | 较大,约2倍 |
文件
xxx.sdi: 存储表结构信息
xxx.MYD:存储数据
xxx.MYI:存储索引
对于数据的一致性要求高,是重要的数据,要求事务的就选用innodo引擎,对数据的一致性要求不高,偶尔丢失一两条数据也没关系的,例如日志信息,足迹信息等,就可以选用Myisam引擎(但目前市场上该需求主要被mangodb代替了)
索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。
B+Tree索引
MySQL索引数据结构对经典的B+Tree进行了优化,在原B+Tree的基础上,增加了一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问性能
B+Tree只在叶子节点存储数据,而BTree在叶子和非叶子都存储数据
Hash索引
1.Hash索引只能用于对等比较(=,in),不支持范围查询(between,>, <, …)
2.无法利用索引完成排序操作
3.查询效率高,通常只需要一次检索就可以了,效率通常要高于B+Tree索引
Hash索引只有Memory引擎支持
为什么InnoDB存储引擎选择使用B+tree索引结构?
Innodb引擎的聚簇索引(主键索引)的叶子节点上存放的是数据本身,而MyISAM引擎(默认非聚簇索引)的聚簇索引和非聚簇索引(二级索引,辅助索引)的叶子节点存放的是指向数据的物理地址
聚集索引也叫聚簇索引
一般会用主键构建聚集索引,叶子节点中除了主键值,还有这条数据的具体信息;而二级索引就是用户自己增加的唯一索引,普通索引这种,它们都是采用B+tree的数据结构存储,但二级索引的叶子节点存储的是这个字段以及主键值
InnoDB主键索引的B+tree高度为多高呢
假设:一行数据的大小为1k,一页中可以存储16行这样的数据。InnoDB的指针占用6个字节的空间,主键即使为bigint,占用字节数8
因此数据如果大概超过2000w的数量级,需要开始考虑分库分表
create index 索引名 on 表名(字段名);
create unique index 索引名 on 表名(phone);
create index 索引名 on 表名(字段1,字段2,字段3);
drop index 索引名 on 表名;
show index from 表名 (查询表的全部索引)
show global status like ‘Com_______’;
可以查看当前数据库的insert、update、delete、select的访问频次
慢查询日志记录了所有执行时间超过指定参数(long_query_time, 单位:秒,默认10秒)的所有SQL语句的日志。
MySQL的慢查询日志默认没有开启
show variables like ‘slow_query_log’;查看是否有开启
SHOW VARIABLES LIKE ‘long_query_time’; 查看慢查询阈值
开启MySQL慢日志查询开关
set global slow_query_log=1;
这种开启慢查询日志只对当前数据库生效,如果MySQL重启则失效。
若想永久生效,久必须修改配置文件my.cnf, [mysqld]下增加或修改参数如下:
[mysqld]
slow_query_log=1
slow_query_log_file=/var/lib/mysql/atguigu-slow.log
long_query_time=3
log_output=FILE
设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
set global long_query_time=2
log_queries_not_using_indexs
这也是慢查询日志中的一个参数,如果允许的SQL语句没有使用索引,则Mysql数据库同样会将该条sql语句记录到慢查询日志文件中。
show variables like ‘log_queries_not_using_indexes’\G; 查看是否打开了该参数
MySQL 5.6.5版本开始新增了一个参数log_throttle_queries_not_using_indexes,用来表示每分钟允许记录到 slow log(Mysql 5.1开始可以将慢查询日志记录放入到一张slow_log表中)的且未使用索引的SQL语句次数,默认值未0,表示没有限制。
但是随着日志的不断增加,后续要分析日志将会变得不那么直观。可以通过mysqldumpslow命令
mysqldumpslow -s al -n 10 david.log;获取执行时间最长的10条SQL语句
执行一系列的业务SQL的操作,然后通过如下指令查看指令的执行耗时:
# 查看每一条SQL的耗时基本情况
show profiles;
# 查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query query_id;
# 查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query query_id;
explain select xxxxx 或者 desc select xxx 可以查询这个查询语句的执行计划,具体参数含义如下:
一般select不访问表的时候才会为NULL,因此在实际业务中不太可能优化到NULL
查找使用了索引,但是需要回表查询数据
Using index 和 Using where 的同时出现表示查询利用了索引加速数据检索,并在索引扫描后使用了额外的条件过滤来获取最终的结果。这通常是一个相对高效的执行计划,但仍然需要考虑索引的选择性、数据量和其他查询条件对性能的影响。
重点例子
该表是有 age_name的联合索引,没有单独的name索引,这里的where只用了 name字段
不符合最左前缀法则,但通过Extra得知任然使用了索引,而type又为index,所以真实是走了索引,但是因为缺少联合索引的最左字段age,没有了顺序,因此它是遍历了索引树,根据name的条件找到了数据,所以Extra中还有Using where,因为该表只有三个字段 id,age,name ,所以该联合索引的目标叶子节点上有需要的所有数据,不再需要回表,
该属性与using index相反,查询的列并没有被索引覆盖,需用用未建立索引的字段进行数据过滤,有两种情况
1.where name = 1 ,name字段并没有设置索引(因此没走索引,走全表,但又需要用name进行过滤
2.where name > 1, 由于数据分布,导致mysql最终没有选择走索引(nam>1的数据选择性太高,优化器认为走全表扫描更快)也是没走索引,走全表,但也需要name字段进行过滤
如果索引了多列(联合索引),要遵守最左前缀法则,最左前缀法则指的是查询从索引最左列开始,并且不能跳过索引中的列。 最左的列只需要存在即可,顺序可以不按照索引顺序
如果跳跃某一列,索引将部分失效(后面的字段索引失效)
联合索引中,出现范围查询(>,<),范围查询右侧的索引失效
可以用 >= 的方式来让右侧的索引不失效
不要在索引列上进行运算操作,索引将失效
explain select * from tb_user where substring(phone, 10, 2) = ‘15’;
字符串类型字段使用时,不加引号,依然能查询到数据,但是索引将失效
explain select * from tb_user where phone = 17799990015;
如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。
用or分隔开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到,只有两个都有索引才会走索引
如果or前后的两个字段是联合索引,依然不会走索引,and的时候才会走
如果and连接的两个字段 a,b都是单列索引,那么mysql将只走一个索引,or的时候则两个都会走
如果MySQL评估使用索引比全表更慢,则不使用索引。(如果要查询的数据占全数据的大部分则则全表,否则走索引)
同理,is null 和 is not null也会根据实际该字段的数据分布,如果大部分都是null,则 is null不走索引,反之
select * from tb_user where phone >= ‘17799990005’; 走全表扫描
select * from tb_user where phone >= ‘17799990015’; 走索引
SQL提示,是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。
1.use index:
建议使用索引,sql可能不接受
explain select * from tb_user use index(索引名) where profession = ‘xxxx’;
2.ignore index
忽略 该索引
3.force index
强制使用该索引
当字段类型为字符串(varchar,text等)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘IO,影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。
create index 索引名 on 表名(字段名(截取的位数));
前缀长度
可以根据索引的选择性来决定,而选择性是指不重复的索引值和数据表的记录总数的比值,索引选择性越高则查询效率越高,唯一索引的选择性是1.
select count(distinct email) / count() from tb_user; 查询去重的email数量占总数的多少,如果为1代表 唯一
select count(distinct substring(email, 1 , 5))/ count() from tb_user; 截取email从1开始的5个字符,并去重后占总数的多少
事务A,读取到了事务B还未提交的更改后的数据
事务A,读取到了事务B已经提交了的数据,和之前读取未提交的数据不一致,导致了不可重复读
事务A查询不到某条数据,但是插入该条数据就会报错已存在
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
READ UNCOMMITTED(读未提交):事务中的修改即使未提交也是对其它事务可见
READ COMMITTED(读提交):事务提交后所做的修改才会被另一个事务看见,可能产生一个事务中两次查询的结果不同。
REPEATABLE READ(可重读):只有当前事务提交才能看见另一个事务的修改结果。解决一个事务中两次查询的结果不同的题。
SERIALIZABLE(串行化):只有一个事务提交之后才会执行另一个事务。