3 explain分析SQL的执行计划
4 简单的优化方法
分析和存储表的关键字分布
分析的结果可以使得系统得到准确的统计信息使得sql,能够生成正确的执行计划。如果用户感觉实际执行计划并不预期的执行计划,执行一次分析表可能会解决问题
mysql> analyze table payments;
检查表
检查一个表或多个表是否有错误,也可以检查视图是否错误
check table payment;
优化表
如果删除了表的一大部分,或者如果已经对可变长度的行表(含varchar、blob、text列)的表进行改动,则使用optimize 进行表优化,这个命令可以使表中的空间碎片进行合并、并且可以消除由于删除或者更新造成的空间浪费
optimize table payment;
对于innodb引擎的表,可以通过设置innodb_file_per_taable参数,设置InnoDb为独立表空间模式,这样每个数据库的每个表都会生成一个独立的idb文件,用于存储表的数据和索引,可以一定程度减少Innodb表的空间回收问题,另外,在删除大量数据后,Innodb表可以通过alter table但是不锈钢引擎方式来回收不用的空间
alter table payment enigine=innodb;
ANALYZE,CHECK,OPTIMIZE,ALTER TABLE执行期间都是对表进行锁定,因此要在数据库不频繁的时候执行相关的操作
拆分表
分区将数据在物理上分隔开,不同分区的数据可以制定保存在处于不同磁盘上的数据文件里。
这样,当对这个表进行查询时,只需要在表分区中进行扫描,而不必进行全表扫描,明显缩短了查询时间,
另外处于不同磁盘的分区也将对这个表的数据传输分散在不同的磁盘I/O,一个精心设置的分区可以将数据传输对磁盘I/O竞争均匀地分散开。
对数据量大的时时表可采取此方法。可按月自动建表分区。
存储过程与触发器的区别
两者唯一的区别是触发器不能用EXECUTE语句调用,而是在用户执行Transact-SQL语句时自动触发(激活)执行。
触发器是在一个修改了指定表中的数据时执行的存储过程。
通常通过创建触发器来强制实现不同表中的逻辑相关数据的引用完整性和一致性。
触发器不同于存储过程,触发器主要是通过事件执行触发而被执行的,
存储过程可以通过存储过程名称名字而直接调用。
当对某一表进行诸如UPDATE、INSERT、DELETE这些操作时,SQLSERVER就会自动执行触发器所定义的SQL语句,从而确保对数据的处理必须符合这些SQL语句所定义的规则。
面试回答数据库优化问题从以下几个层面入手
(1)、根据服务层面:配置mysql性能优化参数;
(2)、从系统层面增强mysql的性能:优化数据表结构、字段类型、字段索引、分表,分库、读写分离等等。
(3)、从数据库层面增强性能:优化SQL语句,合理使用字段索引。
(4)、从代码层面增强性能:使用缓存和NoSQL数据库方式存储,如MongoDB/Memcached/Redis来缓解高并发下数据库查询的压力。
(5)、减少数据库操作次数,尽量使用数据库访问驱动的批处理方法。
(6)、不常使用的数据迁移备份,避免每次都在海量数据中去检索。
(7)、提升数据库服务器硬件配置,或者搭建数据库集群。
(8)、编程手段防止SQL注入:使用JDBC PreparedStatement按位插入或查询;正则表达式过滤(非法字符串过滤);
大批量的插入数据
当用load导入数据,适当的设置可以提供导入的速度
对于MyISAM存储引擎的表,可以通过以下方式快速导入大量的数据
alter table tab_name disable keys; loading the data alter table tab_name disable keys;
disable keys和enable keys 用来打开或者关闭MyISAM表非索引的更新。在导入大量的数据到一个非空的MyISAM表,通过设置这两个命令,可以提高导入的效率
对于Innodb类型的表不能使用上面的方式提高导入效率
因为Innodb类型的表是按照主键的顺序保存,所有将导入的数据按照主键的顺序排序,可以有效地提高导入数据的效率
在导入数据强执行SET UNIQUE_CHECKS=0,关闭唯一性校验,在导入结束后执行SET UNIQUE_CHECKS=1.恢复唯一性校验,可以提高导入的效率,如果应用使用自动提交的方式,建议在导入前执行SET AUTOCOMMIT=0时,关闭自动提交,导入结束后再执行SET AUTOCOMMIT=1,打开自动提交,也可以提高导入的效率
优化insert语句
- 如果同时从一个客户端插入很多行,应尽量使用多个值表的insert语句,这种方式将大大缩减客户端与数据库之间的连接、关闭等消耗,使得效率比分开执行的单个insert语句快(大部分情况下,使用多个值表的insert语句那比单个insert语句快上好几倍)。
insert into test values(1,2),(1,3)...
如果从不同客户插入很多行,可以通过使用insert delayed语句提高更高的速度,delayed的含义是让insert语句马上执行,其实数据都被放到内存的队列中,并没有真正写入磁盘,这比每条语句分别插入要快的多;LOW_PRIORITY刚好相反,在所有其他用户对表的读写完成后才可以进行
将索引文件和数据文件分在不同的磁盘上存放(利用建表中的选项)
如果进行批量插入,可以通过增加bulk_insert_buffer_size变量值的方法来通过速度,但是,这只能对MyISAM表使用。
当从一个文本文件装载一个表时,使用LOAD DATA INFILE。这通常比使用很多INSERT语句块快20倍
优化ORDER BY语句
- 第一种通过有序排序索引顺序扫描,这种方式在使用explain分析查询的时候显示为Using Index,不需要额外的排序,操作效率较高-innodb引擎
explain select customer_id from customer order by store_id;
第二张通过返回数据进行排序,也就是通常说的Filesort排序,所有不是通过索引直接返回排序结果的排序豆角Filesort排序。Filesort并不代表通过磁盘文件进行排序,而只是说明进行了一个排序操作,至于排序操作是否进行了磁盘文件或临时表等,则取决于MySql服务器对排序参数的设置和需要排序数据的大小-myshim引擎
explain select * from customer order by store_id;
Filesort是通过相应的排序算法,将取得的数据在sort_buffer_size系统变量设置的内存排序区进行排序,如果内存装载不下,它会将磁盘上的数据进行分块,再对各个数据块进行排序,然后将各个块合并成有序的结果集。sort_buffer_size设置的排序区是每个线程独占的,所有同一个时刻,MySql存在多个sort buffer排序区
Filesort是通过相应的排序算法,将取得的数据在sort_buffer_size系统变量设置的内存排序区进行排序,如果内存装载不下,它会将磁盘上的数据进行分块,再对各个数据块进行排序,然后将各个块合并成有序的结果集。sort_buffer_size设置的排序区是每个线程独占的,所有同一个时刻,MySql存在多个sort buffer排序区
优化group by 语句
如果查询包括group by 但用户想要避免排序结果的消耗,可以指定group by null
优化嵌套查询
子查询可以被更有效率的连接替代
explain select * from customer where customer_id not in(select customer_id from payment) explain select * from customer a left join payment b on a.customer_id=b.customer_id where b.customer id is null
连接之所用更有效率是因为mysql不需要在内存中创建临时表来完成这个逻辑上需要两个步骤的查询工作
优化分页查询
一般分页查询,通过创建覆盖索引能够比较好地提高性能。一个场景是"limit 1000,20",此时Mysql排序出前1020条数据后仅仅需要返回第1001到1020条记录,前1000条数据都被抛弃,查询和排序代价非常高
优化方式:可以增加一个字段last_page_record.记录上一页和最后一页的编号,通过
explain select ...where last_page_record<... desc limt ..
如果排序字段出现大量重复字段,不适用这种方式进行优化