对于mysql数据库优化的见解
一、数据库占用的空间大小、表占用空间大小、索引占用空间大小
在用阿里云的数据库的时候经常出现磁盘空间爆满的情况。所以要经常查询数据库相关内容占用的磁盘大小,有很多mysql客户端如navicat 就可以直接查看数据库表的一些基本信息。也可以通过MySQL的 information_schema 数据库,查询数据库中每个表占用的空间、表记录的行数;
该库中有一个 TABLES 表,这个表主要字段分别是:
TABLE_SCHEMA : 数据库名
TABLE_NAME:表名
ENGINE:所使用的存储引擎
TABLES_ROWS:记录数
DATA_LENGTH:数据大小
INDEX_LENGTH:索引大小
查看一个表占用空间的大小,那就相当于是 数据大小 + 索引大小 。
1、查询所有数据库占用磁盘空间大小的SQL语句:
SELECT TABLE_SCHEMA, CONCAT(TRUNCATE(SUM(data_length)/1024/1024,2),' MB') AS data_size, CONCAT(TRUNCATE(SUM(index_length)/1024/1024,2),'MB') AS index_size FROM information_schema.tables GROUP BY TABLE_SCHEMA ORDER BY data_length DESC;
2、查询单个库中所有表磁盘占用大小的SQL语句:其中TableName 是 数据库的名称
select TABLE_NAME, concat(truncate(data_length/1024/1024,2),' MB') as data_size, concat(truncate(index_length/1024/1024,2),' MB') as index_size from information_schema.tables where TABLE_SCHEMA = 'TableName' group by TABLE_NAME order by data_length desc;
3、查询单个数据库的大小
use information_schema;
SELECT CONCAT(ROUND(SUM(data_length/1024/1024),2),'MB') AS DATA FROM TABLES WHERE table_schema='DbName';
4、查看指定数据库的某个表的大小
use information_schema;
select concat(round(sum(data_length/1024/1024),2),'MB') as data from tables where table_schema='DbName' and table_name='TableName';
5、查看mysql数据库表的基本信息 :SHOW TABLE STATUS LIKE ‘TableName’
二、慢sql优化的几个思路
本人在实际的开发过程中,一般都是先将数据库设计好,然后开发编写sql,在实际的运行的过程中如果发现有哪些sql执行比较慢,然后再去针对性的去进行优化。
下面列举了一些慢sql执行速度优化的思路:
1、对索引的充分利用:慢sql优化的最主要的思路就是让sql充分的利用索引,避免进行全表扫描。
1.1、索引是提高数据库性能的最常用办法,一般情况下使用索引会让sql的查询速度显著提高。索引能提高查询速度,同时也会降低插入、修改和删除的速度,所以索引并不是越多越好。
1.2、并不是所有的列都适合创建索引,如果该列值的种类比较少如只有0和1,则索引的效果不大,无需在该列上建立索引。
1.3、where条件对某个字段进行判断时尽量不要使用null ,这样如果该列有索引,就无法使用索引。可以在列默认生成的数据用0或者‘’来代替。
1.4、对于like 字段如果左边没有模糊匹配,那么是可以运用该字段上的索引的。
1.5、尽量避免在 where 子句中的“=”左边进行算术运算或其他表达式运算操作,这样可能会无法使用索引。也不要进行函数操作。
1.6、order by 后面的字段如果要使用索引,也是需要从左边开始匹配。
1.7、如果where子句中有一张表中多个字段的判断条件,可以创建联合索引(复合索引);复核索引的第一个字段也可以作为单列索引。如复合索引的列为(A,B)那么where 子句中有字段A也可以使用该复合索引。
1.8、多表关联时确保USING字句中的列上有索引。如果是ON 则要保证被关联的表的该字段上有索引。
2、对表字段的设计:设计表字段的类型,尽量节约空间。
2.1、数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。
2.2、如果字符串数据长度不是固定的,尽量使用varchar。
2.3、对整数类型指定宽度,比如INT(11),这并没有用。INT使用32位(4个字节)存储空间,那么它的表示范围已经确定,所以INT(1)和INT(20)对于存储和计算是相同的。
3、其他细节:
3.1、尽量不要用select * ,直接写需要的字段,减少数据的传输。
三、EXPLAIN 的使用
在实际开发过程中,如果我们已经定位到了一条sql运行速度很慢,那就需要对这个sql运行情况进行分析。那么EXPLAIN就派上用场了。我们直接在要分析的sql前面加上 EXPLAIN执行就能得到下面的内容:
EXPLAIN SELECT * FROM `sys_user` WHERE id NOT IN (SELECT id FROM `sys_user` WHERE id NOT IN (1000,1001,1002,1003))
下面来分析每个字段的含义:
id:mysql执行计划中的ID,ID如果相同,可以认为是一组,从上往下顺序执行,在每组中,其中ID越大,优先级越高,越先执行。
select_type:显示查询中每个select子句的类型
(1) SIMPLE(简单SELECT,不使用UNION或子查询等)
(2) PRIMARY(查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)
(3) UNION(UNION查询中的第二个或后面的SELECT语句)
(4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)
(5) UNION RESULT(从 union 临时表检索结果的 select)
(6) SUBQUERY(包含在 select 结果中的子查询(不在 from 子句中))
(7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,取决于外面的查询)
(8) DERIVED(包含在 from 子句中的子查询。MySQL会将结果存放在一个临时表中,也称为派生表(derived的英文含义))
(9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)
table:显示这一行的数据是关于哪张表的,当 from 子句中有子查询时,table列是 <derivenN> 格式,表示当前查询依赖 id=N 的查询,于是先执行 id=N 的查询。当有 union 时,UNION RESULT 的 table 列的值为 <union1,2>,1和2表示参与 union 的 select 行id。
type:表示MySQL在表中找到所需行的方式,又称“访问类型”。常用的类型有: ALL, index,range,index_subquery,unique_subquery ,index_merge ,ref_or_null ,fulltext , ref, eq_ref, const, system, NULL(从左到右,性能从差到好)
ALL:Full Table Scan, 全表扫描,意味着mysql需要从头到尾去查找所需要的行。通常情况下这需要增加索引来进行优化了
index: Full Index Scan,index与ALL区别为index类型只遍历索引树
range:范围扫描通常出现在 in(), between ,> ,<, >= 等操作中。使用一个索引来检索给定范围的行。
idnex_merge:表示使用了索引合并的优化方法。 例如下表:id是主键,tenant_id是普通索引。or 的时候没有用 primary key,而是使用了 primary key(id) 和 tenant_id 索引
ref_or_null:类似
ref
,但是可以搜索值为NULL的行
ref: 使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行。
eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system
NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
possible_keys:指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用
key:显示MySQL实际决定使用的键(索引)
key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)不损失精确性的情况下,长度越短越好
ref:表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
rows:表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数
filtered:
Extra:MySQL解决查询的详细信息,有以下几种情况:
Using where:列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤
Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询
Using filesort:MySQL中无法利用索引完成的排序操作称为“文件排序”
Using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。
Impossible where:这个值强调了where语句会导致没有符合条件的行。
Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行