赞
踩
目录
对比
MyISAM
InnoDB
主外键
不支持
支持
事务
不支持
支持
行表锁
表锁,操作时即使操作一条记录也会锁住一整张表,不适合高并发的操作
行锁,操作时只锁住某一行,不会影响到其他行,适合高并发
缓存
只缓存索引,不缓存其他数据
缓存索引和真实数据,对内存要求较高,而且内存大小对性能有影响
表空间
小
大
关注点
性能
事务
默认安装
Y
Y
查询语句写的差
索引失效
关联查询太多join (设计缺陷或不得已的需求)
服务器调优及各个参数设置(缓冲,线程参数)
手写
机读先从from开始
a表
mysql> select * from tbl_dept;
±—±---------±-------+
| id | deptName | locAdd |
±—±---------±-------+
| 1 | RD | 11 |
| 2 | HR | 12 |
| 3 | MK | 13 |
| 4 | MIS | 14 |
| 5 | FD | 15 |
±—±---------±-------+
5 rows in set (0.00 sec)
b表
±—±-----±-------+
| id | name | deptId |
±—±-----±-------+
| 1 | z3 | 1 |
| 2 | z4 | 1 |
| 3 | z5 | 1 |
| 4 | w5 | 2 |
| 5 | w6 | 2 |
| 6 | s7 | 3 |
| 7 | s8 | 4 |
| 8 | s9 | 51 |
±—±-----±-------+
8 rows in set (0.00 sec)
mysql不支持全连接
使用以下方式可以实现全连接
mysql> select * from tbl_dept a right join tbl_emp b on a.id=b.deptId
-> union
-> select * from tbl_dept a left join tbl_emp b on a.id=b.deptId;
±-----±---------±-------±-----±-----±-------+
| id | deptName | locAdd | id | name | deptId |
±-----±---------±-------±-----±-----±-------+
| 1 | RD | 11 | 1 | z3 | 1 |
| 1 | RD | 11 | 2 | z4 | 1 |
| 1 | RD | 11 | 3 | z5 | 1 |
| 2 | HR | 12 | 4 | w5 | 2 |
| 2 | HR | 12 | 5 | w6 | 2 |
| 3 | MK | 13 | 6 | s7 | 3 |
| 4 | MIS | 14 | 7 | s8 | 4 |
| NULL | NULL | NULL | 8 | s9 | 51 |
| 5 | FD | 15 | NULL | NULL | NULL |
±-----±---------±-------±-----±-----±-------+
9 rows in set (0.00 sec)
a的独有和b的独有
mysql> select * from tbl_dept a left join tbl_emp b on a.id=b.deptId where b.id is null
-> union
-> select * from tbl_dept a right join tbl_emp b on a.id=b.deptId where a.id is null;
±-----±---------±-------±-----±-----±-------+
| id | deptName | locAdd | id | name | deptId |
±-----±---------±-------±-----±-----±-------+
| 5 | FD | 15 | NULL | NULL | NULL |
| NULL | NULL | NULL | 8 | s9 | 51 |
±-----±---------±-------±-----±-----±-------+
2 rows in set (0.01 sec)
索引的定义:
索引是帮助SQL高效获取数据的数据结构,索引的本质:数据结构
可以简单的理解为:排好序的快速查找数据结构
在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式(引用)指向数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引,下图就是一种示例:
一般来说索引也很大,因此索引往往以索引文件的方式存储在磁盘上
我们平常所说的索引,如果没有特别指明,一般都是指B树(多路搜索树,不一定是二叉的)结构组织的索引,
其中聚集索引,次要索引,复合索引,前缀索引,唯一索引默认都是使用B+树索引,统称索引,当然除了B+树这种类型的索引之外,还有哈希索引。
目录
1.优势
类似大学图书馆图书编号建索引,提高了数据检索的效率,降低数据库的IO成本
通过索引对数据进行排序,降低数据排序的成本,降低了CPU的消耗
2.劣势
实际上索引也是一张表,该表保存了主键与存在索引的字段,并指向实体表的记录,所以索引列也是占用空间的
虽然索引大大提高了查询速度,但是会降低更新表的速度,比如 update,insert,delete操作,因为更新表时,MySQL不仅要数据也要保存索引文件每次更新添加了索引的字段,都会调整因为更新所带来的键值变化后的索引信息
索引只是提高效率的一个因素,在一个大数据量的表上,需要建立最为优秀的索引或者写优秀的查询语句,而不是加了索引就能提高效率
单值索引
唯一索引
复合索引
基本语法:
创建
create [unique] index indexName on mytable(cloumnname(length));
alter mytable add [unique] index [indexName] on (columnname(length));
删除
drop index [indexName] on mytable
查看
show index from table_nameG
有四种方式来添加数据表的索引
BTree索引
Hash索引
full-text全文索引
R-Tree
主键自动建立唯一索引
频繁作为查询条件的字段应该创建索引
查询中与其他表相关联的字段,外键关系建立索引
频繁更新的字段不适合创建索引,因为每次更新不单单更新了记录还更新了索引
where条件里用不到的字段不要创建索引
单键/组合索引的选择问题 who?(高并发下建议组合索引)
查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
查询中统计或分组字段
表记录少
经常操作dml语句的表
数据重复且平均分布的表字段,因此只为最经常查询和最经常排序的数据列建立索引,注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果
explian重点
能干什么
表的读取顺序
数据读取操作的操作类型
哪些索引可以被使用
哪些索引被实际使用
表之间的引用
每张表有多少行被优化器查询
id三种情况
id 相同,执行顺序由上至下
id不同,如果是子查询,id序号递增,id越大优先级越高
id相同不同 ,同时存在
select_type
SIMPLE 简单查询
PRIMARY 主查询 (最外层的查询)
SUBQUERY 子查询
DERIUED 某个查询的子查询的临时表
UNION 联合查询
UNION RESULT 联合查询结果
type::
type显示的是访问类型排列,是较为重要的一个指标
从最好到最差依次是:
system > const > eq_ref> ref > range > index > ALL;
一般来说,得保证查询至少达到range级别,最好ref
----------------------------------------------type类型-------------------------------------------------------
system:表只有一行记录(等于系统表) 这是const类型的特列 一般不会出现,可忽略不计
const:表示通过索引一次就查询到了,const用来比较primary key或者unique索引。因为只匹配一行数据,所以很快,如将主键置于where列表中,Mysql就能将该查询转换为一个常量
eq_ref:唯一性索引扫描,表中只有一条记录与之匹配,常用于主键或唯一索引扫描(两个表是多对一或者一对一的关系,被连接的表是一的情况下,他的查询是eq_ref)
ref:非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它返回匹配某个单独值的所有行,然而他可能会找到多个复合条件的行,属于查找和扫描的结合体
range:只检索给定范围的行,使用一个索引来选择行,key列显示使用了哪个索引,一般where语句里出现了betweent,<,>,in等的查询,这种范围扫描索引比全表扫描好
index:index与ALL的区别,index只遍历索引树,索引文件通常比数据文件小
ALL:全表扫描
----------------------------------------------type类型-------------------------------------------------------
possible_keys:显示可能应用的的索引(理论上)
key:实际使用的索引,查询中若使用了覆盖索引,则该索引仅仅出现在key中
**key_len:**表示索引中使用的字节数,在不损失精度的情况下越短越好,kenlen显示的值为索引字段的最大可能长度,并非实际使用长度,kenlen是根据表定义计算而得,而不是通过表内检索出的
key_len长度:13是因为char(4)*utf8(3)+允许为null(1)=13
**ref:**显示索引的哪一列被使用了,如果可能的话是一个常数,哪些列或常量被用于查找索引列上的值
rows:根据表统计信息及索引选用情况,大致计算出找到所需的记录所需要读取的行数
没建立索引时查询t1 t2表 t1表对应t2表的id t2表 col1的值要为’ac’
对于Id这个字段t1表对t2表相当于 一对多
t1表的type为 eq_ref代表唯一性索引扫描,表中只有一条记录与之匹配,t2表对应t1的这个id对应的col值只有一个,根据t2表的主键id索引查询,t1表读取了一行,t2表读取了640行
建立索引后
t1读取一行,t2读取142行,ref非唯一性索引扫描,返回匹配某个单独值的所有行,返回t2对应id的col所有行,而t1对应id的col只有一行,所以type为eq_ref
包含不适合在其他列展现但十分重要的信息
G :竖直显示排序
Using filesort:说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取,mysql中无法利用索引完成排序的操作称为文件排序未被方框框住的图建立了复合索引,但是直接使用col3进行排序导致空中楼阁,mysql不得已只能进行filesoft
Using temporary:使用了临时表保存中间中间结果,MySQL在对查询结果排序时使用临时表。常见于order by排序和group by分组上表中建立了复合索引 col1_col2 但是直接通过col2进行分组导致了mysql不得已只能进行filesoft和建立临时表
using index 表示相应的select操作中使用了覆盖索引,避免访问了表的数据行,如果同时出现using where 表示索引被用来执行索引键值的查找,没有usingwhere表示索引用来读取数据而非执行查找动作
using where 表示使用了 where过滤
using join buffer 私用了链接缓存
impossible buffer where子句的值总是false 不能用来获取任何元组
select tables optimized away 在没有group by子句的情况下,基于索引优化min/max操作,或者对myisam存储引擎执行count(*)操作,不必等到执行操作进行,查询执行计划生成的阶段即完成优化
distinct 优化distinct操作,在找到第一匹配的元组后立即停止查找同样值的操作
案例
单表优化
CREATE TABLE IF NOT EXISTS `article`(
`id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`author_id` INT (10) UNSIGNED NOT NULL,
`category_id` INT(10) UNSIGNED NOT NULL ,
`views` INT(10) UNSIGNED NOT NULL ,
`comments` INT(10) UNSIGNED NOT NULL,
`title` VARBINARY(255) NOT NULL,
`content` TEXT NOT NULL
);
INSERT INTO `article`(`author_id`,`category_id` ,`views` ,`comments` ,`title` ,`content` )VALUES
(1,1,1,1,‘1’,‘1’),
(2,2,2,2,‘2’,‘2’),
(1,1,3,3,‘3’,‘3’);SELECT * FROM ARTICLE;
mysql> select id,author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;
±—±----------+
| id | author_id |
±—±----------+
| 3 | 1 |
±—±----------+
1 row in set (0.00 sec)mysql> explain select author_id from article where category_id = 1 and comments > 1 order by views desc li
imit 1;
±—±------------±--------±-----------±-----±--------------±-----±--------±-----±-----±---------±----------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
±—±------------±--------±-----------±-----±--------------±-----±--------±-----±-----±---------±----------------------------+
| 1 | SIMPLE | article | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 33.33 | Using where; Using filesort |
±—±------------±--------±-----------±-----±--------------±-----±--------±-----±-----±---------±----------------------------+
1 row in set, 1 warning (0.00 sec)
可以看出虽然查询出来了 但是 type是all,Extra里面出现了using filesort证明查询效率很低
需要优化
建立索引
create index idx_article_ccv on article(category_id,comments,views);
查询
mysql> explain select author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;
±—±------------±--------±-----------±------±----------------±----------------±--------±-----±-----±---------±--------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
±—±------------±--------±-----------±------±----------------±----------------±--------±-----±-----±---------±--------------------------------------+
| 1 | SIMPLE | article | NULL | range | inx_article_ccv | inx_article_ccv | 8 | NULL | 1 | 100.00 | Using index condition; Using filesort |
±—±------------±--------±-----------±------±----------------±----------------±--------±-----±-----±---------±--------------------------------------+
1 row in set, 1 warning (0.00 sec)
这里发现type 变为了 range 查询全表变为了 范围查询 优化了一点
但是 extra 仍然 有 using filesort 证明 索引优化并不成功
所以我们删除索引
drop index idx_article_ccv on article;
建立新的索引,排除掉range
create index idx_article_cv on article(category_id,views);
mysql> explain select author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;
±—±------------±--------±-----------±-----±---------------±---------------±--------±------±-----±---------±------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
±—±------------±--------±-----------±-----±---------------±---------------±--------±------±-----±---------±------------+
| 1 | SIMPLE | article | NULL | ref | idx_article_cv | idx_article_cv | 4 | const | 2 | 33.33 | Using where |
±—±------------±--------±-----------±-----±---------------±---------------±--------±------±-----±---------±------------+
1 row in set, 1 warning (0.00 sec)这时候会发现 优化成功 type 变为了ref extra变为了 using where
在这次实验中我又加入了一次试验 发现当建立索引时comments放在最后也是可行的
mysql> create index idx_article_cvc on article(category_id,views,comments);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> explain select author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;
±—±------------±--------±-----------±-----±----------------±----------------±--------±------±-----±---------±------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
±—±------------±--------±-----------±-----±----------------±----------------±--------±------±-----±---------±------------+
| 1 | SIMPLE | article | NULL | ref | idx_article_cvc | idx_article_cvc | 4 | const | 2 | 33.33 | Using where |
±—±------------±--------±-----------±-----±----------------±----------------±--------±------±-----±---------±------------+
1 row in set, 1 warning (0.00 sec)
这里发现了 type仍然是ref,extra也是usingwhere,而只是把索引建立的位置换了一换,把范围查询的字段挪到了最后!!!
双表优化
CREATE TABLE IF NOT EXISTS `class`(
`id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`card` INT (10) UNSIGNED NOT NULL
);
CREATE TABLE IF NOT EXISTS `book`(
`bookid` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`card` INT (10) UNSIGNED NOT NULL
);
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO class(card)VALUES(FLOOR(1+(RAND()*20)));INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSERT INTO book(card)VALUES(FLOOR(1+(RAND()*20)));
INSER
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。