在使用数据库时,能够显示的看到数据库的性能,sql是如何工作的,能够更好的帮助我们去优化数据库,更高效的使用数据库,那么研究之前先抛出一个问题:
如何确定表和查询是否是最优的?
如果你在工作中也有这样的疑问,那么继续跟我一起学习吧!
参考书目:《高可用MySql》2015一版
<一>EXPLAIN:
给出如何执行SELECT语句的信息(EXPLAIN仅对SELECT有效)
语法:
[EXPLAIN|DESCRIBE] [EXTENDED] SELECT select options
检查select命令以查看Mysql优化器是如何执行这个语句的。其结果是优化器预计执行该语句需要的JOIN操作列表
这个命令的最佳用途:确定表是否有最佳索引,从而更精确地定位候选行。还可以使用这个结果测试各种优化器的重载选项。
用EXPLAIN和DESCRIBE命令查看表的列或分区信息,语法如下:
[EXPLAIN|DESCRIBE] [PARTITIONS SELECT* FROM ] table_name
explain各属性详解,参照mysql-explain关键字篇
下面给出一个列子,详细说明索引是否生效?何时生效?如何更高效?
mysql中枚举类型字段:
枚举类型接受一组值得列表,如果不使用枚举类型而是定义一个查找表的话,就必须执行JOIN来选择指定值的结果。因此,枚举类型能代替小型查找表,所以,枚举类型可以提升性能。枚举值的文本只保存一次,在表头结构中,行中保存的时数字值,形成一个枚举值的索引(数组索引)。枚举值列表能够节省空间,使得遍历数据更加有效。一个枚举字段类型只能接受一个值。
枚举类型的误用带来的损失?
1、首先,创建一个表,表名file:
CREATE TABLE `film` (
`id` bigint(20) NOT NULL,
`file_name` varchar(20) default NULL,
`rating` enum('G','PG','PG-13','R','NC-17') default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
如果在创建表时没有给enum类型字段赋值,则需要将数据表中所有用到此enum字段的数据清空,然后再给enum赋值,赋值语句为:
Alter table film modify column rating enum('G','PG','PG-13','R','NC-17',给需要添加的enum值);
2、加入数据
3、一个简单的查询语句
EXPLAIN SELECT * FROM film WHERE rating > 'PG'
执行结果:
id 1
select_type SIMPLE
table film
type ALL
possible_keys null
key null
key_len null
ref null
rows 6
Extra Using where
可以看到,优化器只执行了一步,而且没有使用任何索引,因为没有使用任何索引列。
此外,即使这里包含了一个WHERE子句,但是优化器仍然需要做全表扫描。
4、添加索引改善性能
Alter table film add index film_rating(rating)
再次运行上述查询,运行结果如下:
id 1
select_type SIMPLE
table film
type ALL
possible_keys film_rating
key null
key_len null
ref null
rows 6
Extra Using where
可以看到,查询识别了一个索引,但是仍然没有使用索引,因为key字段是null
5、去掉范围查询
EXPLAIN SELECT * FROM film WHERE rating = 'PG'
执行结果变为:
id 1
select_type SIMPLE
table film
type ref
possible_keys film_rating
key film_rating
key_len 2
ref const
rows 1
Extra Using where
6
、改进后的非范围查询
EXPLAIN SELECT * FROM film WHERE rating = 'R' OR rating = 'NC-17'
执行结果变为:
id 1
select_type SIMPLE
table film
type ALL
possible_keys film_rating
key null
key_len null
ref null
rows 6
Extra Using where
我们同样选择了查询有索引的列,但是优化器却不能使用这个索引
7、使用union
EXPLAIN SELECT * FROM film WHERE rating = 'R'
union
SELECT * FROM film WHERE rating = 'NC-17'
执行结果变为:
***********1.row************************
id 1
select_type PRIMARY
table film
type ref
possible_keys film_rating
key film_rating
key_len 2
ref const
rows 2
Extra Using where
***********2.row************************
id 2
select_type UNION
table film
type ref
possible_keys film_rating
key film_rating
key_len 2
ref const
rows 1
Extra Using where
***********3.row************************
id NULL
select_type UNION RESULT
table
type ALL
possible_keys null
key null
key_len null
ref null
rows null
Extra
可以看到,这个查询计划使用了索引,处理了更少的行,从EXPLAIN命令的结果可以看到优化器单独运行每个查询(从第一行到第n行分步执行),然后再最后一步合并结果。
<二>ANALYZE TABLE:
与大多数传统优化器相同,mysql优化器使用表的统计信息分析最优查询执行计划,这些统计信息涉及多项信息,包括索引、数值分布和表结构
ANALYZETABLE命令重新计算一个或多个表的主键分布。这个信息确定JOIN操作中表的顺序。语法结构为:
ANALYZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE table_list
每当表上有重大变更(如批量加载数据)时,都应该执行这个命令。在执行的时候,系统必须在这个表上加上读锁
智能为MyISAM和InnoDB表更新主键分布。其他存储引擎不支持这个工具,但是如果存储引擎支持索引则所有存储引擎必须将索引的基础统计信息报告给优化器。有些存储引擎,特别是第三方引擎,有他们特有的内置统计信息。
1、 分析表,更新主键分布
ANALYZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE table_list
执行结果:
我们看到分析完成了,并且没有异常出现。
1、 分析错误
如果出现异常,Msg_type将为info、Error、warning,在这些情况下,Msg_text将显示额外的信息。如果你得到的结果不是OK或者status,应该审查一下。
产生错误的例子:
如果.frm文件损坏或者丢失,可以查看以下消息。在其他情况下,输出结果可能表明表示不可读的(比如权限和访问问题)。此外,命令执行了存储引擎相关的检查。
分析表错误:
ANALYZE TABLE test.film1
执行结果:
Table |
Op |
Msg_type |
Msg_text |
test.film1 |
analyze |
Error |
Table ‘test.film1’ doesn’t exist |
Test.film1 |
analyze |
status |
Operation failed |
SHOW INDEX FROM film
执行结果为:
<三>OPTIMIZE TABLE:
频繁使用新数据或删除操作,表将很快变得支离破碎,而且根据使用的存储引擎不同,将会出现不同程度的闲置空间或不理想的存储结构。支离破碎的表可能导致性能下降,尤其是在表扫描的时候。
OPTIMIZE TABLE命令可以重构一个或者多个表的数据结构。对于长度可变的字段(行)而言,这个命令尤其有用,命令的语法如下:OPTIMIZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE table_list
LOCAL或NO_WRITE_TO_BINLOG关键字防止命令被写入二进制日志文件中(因此也不会再复制拓扑中被复制)。如果希望在复制数据时进行实验或调整,或者如果希望从二进制日志中省略这一步,而且在PITR时不再重放,那么这个命令很有用。
每次表上有重大变更(例如大量的删除或插入)时,都应该运行这个命令。这个操作将数据元素重组到更优的结构中,而且可能会运行很长时间(在表上持有写锁)。所以,这个操作最好在低负载的时候运行。
如果表不能被重新组织(例如如果不存在可变长度的记录或者不存在碎片),这个命令将重新创建表,然后更新统计信息。
执行命令:optimize table film
执行结果如下: