什么是索引?
索引就像是指向表中数据的指针,是在基本表上建立的一种数据库对象,与基本表分开存储,索引存在磁盘中。如果我们把书比作数据,那么各个章节就相当于表,书的目录就相当于索引。
假设没有索引,数据库在查询时总是从第一条数据一条条往下遍历,直到查到符合要求的数据。而如果在所要查询的字段上建了索引,数据库就无须全盘遍历就能快速找到对应的数据。其中mysql索引的存储类型大致有两种:B+与哈希,前者底层为多路搜索且叶子节点构成一个有序列表,后者更适合等值查询即如果只选一条数据那速度会非常快,因为只需一次哈希算法即能找到相应的位置。
索引的分类
索引从形式上分为单列索引和组合索引,从类别上可以分为普通索引、唯一索引和主键索引,下面简单介绍下:
单列索引:一个单列索引中只包含一个列,一张表中可以有多个单列索引
组合索引:一个组合索引包含两个或以上的列组合,组合索引生效条件满足最左前缀机制,比如设置组合索引(a,b,c),具体生效原则为:从前往后依次使用生效,如果中间某个索引没有使用,那么断点前面的索引部分起作用,断点后面的索引没有起作用,比如
where a=3 and b=45 and c=5 .... 这种三个索引顺序使用中间没有断点,全部发挥作用;
where a=3 and c=5 ... 这种情况下b就是断点,a发挥了效果,c没有效果
where b=3 and c=4 ... 这种情况下a就是断点,在a后面的索引都没有发挥作用,这种写法联合索引没有发挥任何效果;
where b=45 and a=3 and c=5 .... 这个跟第一个一样,全部发挥作用,abc只要用上了就行,跟写的顺序无关
具体请走:mysql多列索引的生效规则
普通索引(INDEX):是最基本的索引类型,也是用的最多的,一般用在表中数据较多且查询较频繁的那些字段,其基本sql格式为
CREATE INDEX IndexName ON `TableName`(`字段名`) 或
ALTER TABLE TableName ADD INDEX IndexName(`字段名`)
唯一索引(UNIQE INDEX):与普通索引类型,但是它要求所作用的列下不能有重复的值,允许空值,唯一索引的目的并不是为了提高响应速度,而是为了避免数据重复,其基本sql格式为
CREATE UNIQUE INDEX IndexName ON `TableName`(`字段名`); 或
ALTER TABLE TableName ADD UNIQUE IndexName(`字段名`)
主键索引(PRIMARY):主键索引是一种特殊的唯一索引,同样不允许空值,一般在建表的时候即已定义好,不允许空值,其基本sql格式为
CREATE TABLE testIndex(i_testID INT NOT NULL AUTO_INCREMENT,vc_Name VARCHAR(16) NOT NULL,PRIMARY KEY(i_testID)); 或
ALTER TABLE TableName ADD PRIMARY KEY (`id`);
索引的底层实现还是依赖其数据结构,例如B+树,如有需要可出门左转:树型结构小结
mysql优化
1、开启慢查询
谈到优化,那首先就得先知道项目中查询比较慢的sql语句有哪些,我们才能对症下药嘛,这里mysql为我们提供了慢查询的机制,即我们可以通过开启mysql的慢查询来发现我们项目中超过指定时间的sql查询语句。
下面通过命令行的方式开启慢查询,该方式不需要重启mysql服务
首先进入mysql命令,输入如下命令:
show variables like "long%";
上图中的 long_query_time 代表最大查询时间,即一旦sql语句超过该时间则会被输出到慢查询日志中,然后输入:
show variables like "slow%";
上图中的slow_query_log代表慢查询功能,默认是OFF,slow_query_log_file 代表慢查询日志的文件目录,也可自定义。
下面我们通过设置全局的方式开启慢查询功能并设置我们指定的时间,输入如下命令即可:
set global long_query_time = 0.001;
set global slow_query_log = on;
到这里慢查询就已经开启啦,让项目运行下即能输出查询较长的那些语句啦,然后我们就能开始分析这些语句啦。针对那些查询较慢的语句,常用的优化往往是加索引或者是优化表结构。
如果慢查询日志中记录内容很多,可以使用mysqldumpslow工具分析
mysqldumpslow -s c -t 10 /data/3306/slow-query.log
输出记录次数最多的10条SQL语句
-s, 是表示按照何种方式排序,c、t、l、r分别是按照记录次数、时间、查询时间、返回的记录数来排序,ac、at、al、ar,表示相应的倒叙;
-t, 是top n的意思,即为返回前面多少条的数据
2、explain含义
mysql提供了explain语法来分析查询语句,只需在select语句前加上explain关键词,sql的执行计划就一目了然,下面看个小例子来解释下explain运行后所代表的含义
mysql> explain select * from user_info where id = 2
*************************** 1. row ***************************
id: 1 // select查询的标识符,每个select都会自动分配一个唯一的标识符
select_type: SIMPLE // select查询的类型
table: user_info // 查询的是哪个表
partitions: NULL // 匹配的分区
type: const // 连接类型
possible_keys: PRIMARY // 此次查询中可能选用的索引
key: PRIMARY // 此次查询中确切使用到的索引
key_len: 8 // 使用的索引的长度,在不损失精确性的情况下,长度越短越好
ref: const // 显示索引的哪一列被使用了,如果可能的话,是一个常数
rows: 1 // 显示此查询一共扫描了多少行. 这个是一个估计值.
filtered: 100.00 // 表示此查询条件所过滤的数据的百分比
Extra: NULL // 额外的信息
1 row in set, 1 warning (0.00 sec)
接下来挑几个重要的详细解释下:
select_type:表示查询类型,常用取值如下:
SIMPLE:表示此查询不包含 UNION 查询或子查询
PRIMARY:表示此查询是最外层的查询
UNION:表示此查询是 UNION 的第二或随后的查询
DEPENDENT UNION:UNION 中的第二个或后面的查询语句, 取决于外面的查询
UNION RESULT:UNION 的结果
SUBQUERY:子查询中的第一个 SELECT
DEPENDENT SUBQUERY:子查询中的第一个 SELECT, 取决于外面的查询. 即子查询依赖于外层查询的结果.
type:这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为system、const、eq_ref、ref、range、index和all
说明:不同连接类型的解释(按照效率高低的顺序排序)
system:表只有一行:system表。这是const连接类型的特殊情况。
const :表中的一个记录的最大值能够匹配这个查询(索引可以是主键或惟一索引)。因为只有一行,这个值实际就是常数, 因为MYSQL先读这个值然后把它当做常数来对待。
eq_ref:在连接中,MYSQL在查询时,从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为 主键或惟一键的全部时使用。
ref:这个连接类型只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前 的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于根据索引匹配的记录多少—越少越好。
range:这个连接类型使用索引返回一个范围中的行,比如使用>或<查找东西时发生的情况。
index:这个连接类型对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据)。
all:这个连接类型对于前面的每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免。
possible_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句
key:实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,mysql会选择优化不足的索引。这种情况下,可以在select语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制mysql忽略索引
extra:查询的额外信息,这里可以看到最坏的例子是Using temporary和Using filesort,意思mysql根本不能使用索引,结果是检索会很慢
说明:extra列返回的描述的意义
Distinct :一旦mysql找到了与行相联合匹配的行,就不再搜索了。
Not exists :mysql优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索了。
Range checked for each Record(index map:#) :没有找到理想的索引,因此对从前面表中来的每一个行组合,mysql检查 使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一。
Using filesort :看到这个的时候,查询就需要优化了。mysql需要进行额外的步骤来发现如何对返回的行排序。它根据连接类 型以及存储排序键值和匹配条件的全部行的行指针来排序全部行。
Using index :列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同 一个索引的部分的时候。
Using temporary :看到这个的时候,查询需要优化了。这里,mysql需要创建一个临时表来存储结果,这通常发生在对不同的 列集进行ORDER BY上,而不是GROUP BY上。
Where used :使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连 接类型ALL或index,这就会发生,或者是查询有问题。
3、mysql优化
上面提到的慢查询分析及explain其实我项目中就用过没几次,这边主要还是作记录用。下面主要谈下mysql如何优化
a、索引失效的情况
1)使用like关键字,如果匹配字符串的第一个字符为“%”,如 '%XX'或者like '%XX%',索引不会起作用,只有“%”不在第一个位置索引才会起作用。
2)使用组合索引需满足最左前缀机制,注意查看sql语句写法,避免后面的索引因为断点问题导致索引失效
3)不在索引列上进行任何操作,如计算、函数、类型转换,这将会导致索引失效
4)如果列类型是字符串,那一定要在条件中将数据使用引号引用起来
5)如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因),要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
b、优化数据库结构
合理的数据库结构不仅可以使数据库占用更小的磁盘空间,而且能够使查询速度更快。数据库结构的设计,需要考虑数据冗余、查询和更新的速度、字段的数据类型是否合理等多方面的内容。
1)将字段很多的表分解成多个表
对于字段比较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。因为当一个表的数据量很大时,会由于使用频率低的字段的存在而变慢。
mysql存储过程语法
将存储过程的语法顺带记录在这边
创建存储过程:
create procedure test()
begin
.........
end
调用存储过程:
call test();
删除存储过程:
drop procedure test;
其他相关命令:
1.show procedure status //显示数据库中所有存储的存储过程基本信息,包括所属数据库,存储过程名称,创建时间等
2.show create procedure test //显示某一个MySQL存储过程的详细信息