MySQL DBA必读:万字归总表设计与SQL编写技巧( 六 )


方法二:
Insert into tablename values(1,2),(1,3),(1,4);
选择后一种方法的原因有二 。

  • 减少SQL语句解析的操作,MySQL没有类似Oracle的share pool,采用方法二,只需要解析一次就能进行数据的插入操作;
  • SQL语句较短,可以减少网络传输的IO 。
此外,还有以下建议提高插入性能:
  • 通过使用 INSERT DELAYED 语句得到更高的速度 。Delayed 的含义是让 insert 语句马上执行,其实数据都被放在内存的队列中,并没有真正写入磁盘;
  • 这比每条语句分别插入要快的多,但需要注意,DELAYED关键字只用于MyISAM,MEMORY这类只支持表锁的存储引擎;
  • 将索引文件和数据文件分在不同的磁盘上存放(利用建表中的选项) 。
2、查询优先还是更新(insert、update、delete)优先
MySQL 还允许改变语句调度的优先级,它可以使来自多个客户端的查询更好地协作,这样单个客户端就不会由于锁定而等待很长时间 。改变优先级还可以确保特定类型的查询被处理得更快 。我们首先应该确定应用的类型,判断应用是以查询为主还是以更新为主的,是确保查询效率还是确保更新的效率,决定是查询优先还是更新优先 。下面我们提到的改变调度策略的方法主要是针对只存在表锁的存储引擎,比如 MyISAM 、MEMROY、MERGE,对于Innodb 存储引擎,语句的执行是由获得行锁的顺序决定的 。MySQL 的默认的调度策略可用总结如下:
1)写入操作优先于读取操作 。
2)对某张数据表的写入操作某一时刻只能发生一次,写入请求按照它们到达的次序来处理 。
3)对某张数据表的多个读取操作可以同时地进行 。MySQL 提供了几个语句调节符,允许你修改它的调度策略:
  • LOW_PRIORITY关键字应用于DELETE、INSERT、LOAD DATA、REPLACE和UPDATE;
  • HIGH_PRIORITY关键字应用于SELECT和INSERT语句;
  • DELAYED关键字应用于INSERT和REPLACE语句 。
如果写入操作是一个 LOW_PRIORITY(低优先级)请求,那么系统就不会认为它的优先级高于读取操作 。在这种情况下,如果写入者在等待的时候,第二个读取者到达了,那么就允许第二个读取者插到写入者之前 。只有在没有其它的读取者的时候,才允许写入者开始操作 。这种调度修改可能存在 LOW_PRIORITY写入操作永远被阻塞的情况 。SELECT 查询的HIGH_PRIORITY(高优先级)关键字也类似 。它允许SELECT 插入正在等待的写入操作之前,即使在正常情况下写入操作的优先级更高 。另外一种影响是,高优先级的 SELECT 在正常的 SELECT 语句之前执行,因为这些语句会被写入操作阻塞 。如果希望所有支持LOW_PRIORITY 选项的语句都默认地按照低优先级来处理,那么 请使用--low-priority-updates 选项来启动服务器 。通过使用 INSERTHIGH_PRIORITY 来把 INSERT 语句提高到正常的写入优先级,可以消除该选项对单个INSERT语句的影响 。
3、避免出现select *
select * 操作在任何类型数据库中都不是一个好的SQL开发习惯 。使用select * 取出全部列,会让优化器无法完成索引覆盖扫描这类优化,会影响优化器对执行计划的选择,也会增加网络带宽消耗,更会带来额外的I/O,内存和CPU消耗 。建议评估业务实际需要的列数,指定列名以取代select * 。
  • 规范:Select col1,col2,col3… from t1;
  • 不规范:Select * from t1 。
4、避免使用insert..selec..语句
当使用insert...select...进行记录的插入时,如果select的表是innodb类型的,不论insert的表是什么类型的表,都会对select的表的纪录进行锁定 。对于那些从Oracle迁移过来的应用,需要特别的注意,因为Oracle并不存在类似的问题,所以在Oracle的应用中insert...select...操作非常常见 。例如:有时候会对比较多的纪录进行统计分析,然后将统计的中间结果插入到另外一个表,这样的操作因为进行的非常少,所以可能并没有设置相应的索引 。
如果迁移到MySQL数据库后不进行相应的调整,那么在进行这个操作期间,对需要select的表实际上是进行的全表扫描导致的所有记录的锁定,将会对应用的其他操作造成非常严重的影响 。
究其主要原因,是因为MySQL在实现复制的机制时和Oracle是不同的,如果不进行select表的锁定,则可能造成从数据库在恢复期间插入结果集的不同,造成主从数据的不一致 。如果不采用主从复制,关闭binlog并不能避免对select纪录的锁定 。如果使用这个binlog进行从数据库的恢复,或者进行主数据库的灾难恢复,都将可能和主数据库的执行效果不同 。


推荐阅读