MySQL笔记

MySQL笔记

MySQL逻辑分层
	select
	连接层: 提供与客户端连接的服务
	服务层:	1.提供各种用户使用的接口(select..增删改查)
			2.提供SQL查询优化器,优化复杂的SQL语句,写的语句A,执行的B
	引擎层:	提供各种存储数据的方式(InnoDB、MyISAM[看下区别])
		InnoDB:事务优先,适合高并发操作,事务可以防止高并发造成的混乱,行锁
		MyISAM:性能优先,表锁(一次锁一张表)
	存储层:存储数据

	查询数据库引擎:支持哪些引擎? show engines;
					查看当前使用的引擎	show variables like '%storage_engine%';

	指定数据库引擎:
	create table tb(
		id int(4) auto_increment,
		name varchar(5),
		Primary Key(id)
	)ENGINE=MyISAM, AUTO_INCREMENT=1;


SQL优化	
	原因:性能低、执行时间长、SQL语句欠佳(连接查询)、索引失效、服务器参数设置不合理(缓冲区、线程数等等)

	SQL语句
	编写过程:select (distinct.. from .. join .. on .. where .. group by .. having .. order by .. limit ..

	解析过程:from .. on .. join .. where .. group by .. having .. select .. order by .. limit ..

	文章:www.cnblogs.com/annsshadow/p/5037667.html


	SQL优化:主要就是优化索引
		索引:index是数据帮助MYSQL高效获取数据的数据结构,B+树

	索引不适用情况:数据量少、频繁更新的字段、使用少的字段
	优点:提高查询效率(降低IO次数)、B树索引本身就是有序的


索引
	分类:
		单值索引:单列,age,一个表可以有多个单值索引
		唯一索引:不能重复,id,【主键索引】不为NULL
		复合索引:多个列构成的索引(name,age)

	创建索引:
		create 索引类型 索引名 on 表(字段)
		单值索引:create index dept_index on tb(dept);
		唯一索引:create unique index name_index on tb(name);
		复合索引:create index dept_name_index on tb(dept, name);

		alter table 表 add 索引类型 索引名(字段)
		单值索引:alter table tb add index dept_index(dept);
		唯一索引:alter table tb add unique index name_index(name);
		复合索引:alter table tb add index dept_name_index (dept, name);

	删除索引:
		drop index 索引名 on 表;
		drop index name_index on tb;

	查询索引:
		show index from 表;

SQL性能问题
	a.分析SQL的执行计划  explain
	b.MySQL优化器会干扰我们的优化

	优化方法:官网dev.mysql.com/doc/refman/5.5/en/optimization.html

	id:编号
	select_type:查询类型 
	table:表 
	type:类型
	possible_keys:可能用到的索引 
	key:实际用到的索引
	key_len:实际使用索引的长度
	ref:表之间的引用关系
	rows:在查询中估计要读取的行数,不是结果集的行数
	Extra:额外信息

	准备数据:
		create table course(
			cid int(3),
			cname varchar(20),
			tid int(3)
		);

		create table teacher(
			tid int(3),
			tname varchar(20),
			tcid int(3)
		);

		create table teacherCard(
			tcid int(3),
			tcdesc varchar(200)
		);

		insert into course values(1, 'java', 1);
		insert into course values(2, 'html', 1);
		insert into course values(3, 'sql', 2);
		insert into course values(4, 'web', 3);

		insert into teacher values(1, 'tz', 1);
		insert into teacher values(2, 'tw', 2);
		insert into teacher values(3, 'tl', 3);

		insert into teacherCard values(1, 'tzdesc');
		insert into teacherCard values(2, 'twdesc');
		insert into teacherCard values(3, 'tldesc');

		查询课程编号为2或教师证编号为3的老师信息
 		select t.* from teacher t, course c, teacherCard tc where t.tid=c.tid and t.tcid=tc.tcid and (c.cid=2 or tc.tcid=3);


 	id:编号
		(1)id值相同:从上往下顺序执行		t3-tc3-c4
 						teacher 插入三条后:tc3-c4-t6
 			表执行顺序因数量的个数改变而改变的原因:笛卡尔积
 							2 * 3 = 6 * 4 = 24
 							4 * 3 = 12 * 2 = 24	结果一样,中间不一样
 							数据小的表优先查询
 		(2)id值不同,越大越优先查询(本质:嵌套子查询时,先查内层)

 		查询教授sql课程老师的描述(desc)
 		explain select tc.tcdesc from teacherCard tc,teacher t, course c where tc.tcid = t.tcid and c.tid = t.tid and c.cname='sql';

 		将以上多表查询变为子查询形式:
 		explain select tc.tcdesc from teacherCard tc where tc.tcid = 
 		(select t.tcid from teacher t where t.tid = (select tid from course where cname = 'sql'));

 		explain select t.tname, tc.tcdesc from teacher t, teacherCard tc where t.tcid = tc.tcid and t.tid = (select c.tid from course c where cname = 'sql');

 		(3)id有相同又有不同:id值越大越优先,id值相同上到下顺序执行


 	select_type:查询类型 
 		PRIMARY:包含子查询SQL中的主查询(最外层)
 		SUBQUERY:包含子查询SQL中的子查询(非最外层)
 		SIMPLE:简单查询(不包含子查询,union)
 		DERIVED:衍生查询(使用到了临时表)
 				在from子查询中只有一张表
 					select cr.cname from (select * from course where tid in (1, 2)) cr;
 				在from子查询中,有两张表union关系,tb1 union tb2, tb1是DERIVED,tb2是union
 					select cr.cname from (select * from course where tid = 1 union select * from course where tid = 2) cr;
 		UNION:上例
 		UNION RESULT:告知表之间存在union查询

 	table:表 
		
	type:索引类型
		system > const > eq_ref > ref > range > index > all
		system/const理想情况,实际达到ref级别

		system:只有一条数据的系统表,或衍生表只有一条数据的主查询
			create table test01(
				tid int(3),
				tname varchar(20)
			);
			insert into test01 values(1, 'a');
			alter table test01 add constraint tid_pk primary key(tid);
			explain select * from (select * from test01) t where tid=1;

		const:仅仅能查到一条数据的SQL,用于primary key或unique索引(类型与索引类型有关)
			explain select tid from test01 where tid=1;

			alter table test01 drop primary key;

		eq_ref:唯一性索引,对于索引键的查询,返回匹配唯一行数据(有且只有一个)
			常见与唯一索引和主键索引

			alter table teacherCard add constraint pk_tcid primary key(tcid);

			alter table teacher add constraint uk_tcid unique index(tcid);

			select t.tcid from teacher t, teacherCard tc where t.tcid=tc.tcid;

		ref:非唯一性索引,返回匹配的所有行
			insert into teacher values(4, 'tz', 4);
			insert into teacherCard values(4, 'tz222');

			alter table teacher add index idx_name(tname);
			select * from teacher t where tname='tz';
		range:检索指定范围的行,where后是一个范围查询(between..and, >,<,>=, in可能失效)
			alter table teacher add index tid_index(tid);
			explain select t.* from teacher t where t.tid > 3;

		index: 查询全部索引中的数据

		all:查询表中所有的数据

		总结:	system/const:结果只有一条数据
 				eq_ref:结果多条,但每条数据是唯一的
 				ref:结果多条,但每条数据是0条或者多条

	possible_keys:可能用到的索引 
	key:实际用到的索引
	key_len:实际使用索引的长度
	ref:表之间的引用关系
		ref作用:指明当前表所参照的字段
 			select .. where a.c = b.x(引用b的x); (其中b的x可以是常量const)
 			select * from course c, teacher t where c.tid=t.tid and t.tname='tw';
	rows:在查询中估计要读取的行数,不是结果集的行数
	Extra:额外信息

单表优化例子:
	create table info(
		id int(4) primary key,
		name varchar(10),
		age int(4),
		deptId int(4),

	);


两表优化:
	create table teacher(
		tid int(4) primary key,
		cid int(4) not null
	);

	insert into teacher values(1,2);
	insert into teacher values(2,1);
	insert into teacher values(3,3);

	create table course(
		cid int(4),
		cname varchar(10)
	);

	insert into course values(1, 'c++');
	insert into course values(2, 'python');
	insert into course values(3, 'java');

	左连接:
		select * from teacher t left outer join course c on t.cid=c.cid where c.cname='java';

	索引怎么加?  --小表驱动大表,索引建立在经常使用的字段
	where 小表.x=大表.y

	a left on b,建立在a表
	a right on b,建立在b表
	alter table teacher add index idx_cid(cid);
	alter table course add index idx_cname(cname);

	drop index idx_cid on teacher;

	using join buffer:MySQL引擎使用了链接缓冲


多表优化:
	a.小表驱动大表
	b.建立在经常使用的字段上






避免索引失效的原则:
	a.复合索引,不要跨列或无序使用(最佳左前缀)
		where a and b order by c
	b.复合索引,尽量使用全索引匹配	
		找张三,学校-年级-班级
	c.不要在索引上进行操作(计算、函数、类型转换)
		where a.x = ..;
		where a.x*3 = ..;
	d.复合索引不能使用不等于(!=, <>)或is [not] null
	e.like尽量以“常量”开头,不以%或*开头
		explain select * from course where cname like "%x";
		使用索引覆盖可以挽救一部分 select cname ...
	f.不要使用类型转换
		explain select * from course where cname=123;
	g.不使用or
		explain select * from course where cname='1' and cid=2;


一些其他优化方法:
	exist和in
		如果主查询的数据集大,使用in
		如果子查询的数据集大,使用exist
	select .. from table where exist/in (子查询);
	select .. from tablr where id in (1,2);

	order by:
		using filesort有两种算法,双路排序和单路排序(根据IO次数)
		双路排序,扫描两次磁盘,第一次扫描排序字段,第二次扫描其他字段
		单路排序,一次读取所有字段,在buffer中排序
		MySQL4.1之后默认单路(IO消耗性能):一次读取全部字段,在buffer中进行排序,但单路排序会有一定隐患(有可能多次IO)数据量太大,缓存区容量不足,无法一次性读完,因此会”分片读取、多次读取“。

 		单路比双路占用更多buffer,单路排序如果数据大,可以考虑调大buffer的容量大小:set max_length_for_sort_data = 1024;

 		如果max_length_for_sort_data值太低,MySQL自动从单路->双路(太低:需要排序的列总大小超过了定义的字节数)

		提高order by查询:
			1.选择合适的单双路,调整buffer大小
			2.避免select * 
			3.复合索引不要跨列使用,避免using filesort
			4.保证排序字段的一致性,全升序或全降序

SQL排查:
 		慢查询日志:MySQL提供的一种日志记录,用于记录响应时间超过阈值的SQL语句(long_query_time,默认10秒)
 		慢查询日志默认关闭,建议:调优时打开,最终部署时关闭

 		检查是否开启了慢查询日志: show variables like '%slow_query_log%';
 		临时开启:set global slow_query_log = 1; --在内存中开启
 		重启mysql服务恢复默认 service mysql restart;
 		
 		临时设置阈值:set long_query_time=10;完毕后重登起效

 		show global status like '%slow_queries%';



分析海量数据:
	模拟数据: 存储过程/存储函数(return)
	create database testdb;

	create table dept(
		id int(4) primary key default 0,
		dname varchar(10) not null default '',
		loc varchar(10) default ''
	)engine=innodb default charset=utf8;

	create table emp(
		eid int(4) primary key,
		ename varchar(10) not null,
		job varchar(10) not null,
		deptid int(4) not null
	)engine=innodb default charset=utf8;

	通过存储函数插入海量数据
	创建存储函数:

		delimiter $
		create function randstring(n int) returns varcahr(255)
		begin
			declare all_str varchar(255) default 'abcdefghijklmnopqrstuvwxyz';
			declare ret_str varchar(255) default '';
			declare i int default 0;
			while i < n
			do
				set ret_str = concat(ret_str, substring(all_str, FLOOR(rand()*26 + 1), 1));
				set i = i + 1
			end while;
			return ret_str;
		end $















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值