SQL语句优化和MySQL在大数据和高并发场景下的“最佳实践”,“高并发”只针对中小型应用,专业的数据库运维高手请无视。以下实践是个人实际开发工作中针对比较“大数据”和比较“高并发”场景的一些应对策略。有些措施没有经过严格的对比测试和原理分析。如有错误或遗漏,欢迎大家多方批评和建议。减少查询对结果集的影响,避免全表扫描。影响结果集是SQL优化的核心。影响结果集的不是查询返回的记录数,而是查询扫描的结果数。通过Explain或Desc分析SQL,rows列的值为受影响的结果集(也可以从慢查询日志中Rows_examined后面的数字获取)??。以下是我经常使用的一些SQL优化策略:删除不必要的查询和搜索。其实在项目的实际应用中,很多查询条件是可有可无的,应该从源头上尽量砍掉那些可以避免的冗余功能。这是最简单粗暴的解决方法。合理使用索引和复合索引。索引是最有效的SQL优化手段。常用于查找、删除、更新和排序的字段可以被适当地索引。但是需要注意的是,单个查询不能同时使用多个索引,只能使用一个索引。当查询条件较多时,可以使用组合多个字段的复合索引。记住,使用复合索引时,查询条件的字段顺序需要和复合索引的字段顺序保持一致。小心使用notin和其他可能无法使用索引的条件。索引并不总是可用的。当出现“notin”、“!=”、“like'%xx%'”、“isnull”等条件时,索引无效。使用这些条件时,将它们放在可以有效使用索引的条件的右边。在设计表结构时,个人建议尽量使用int类型,不要使用varchar类型。int类型可以用大于或小于“!=”等条件代替。同时也方便满足一些需要按类型排序的需求。至于可读性问题,完善数据库设计文档是明智的选择。同时,建议将所有可能的字段设置为“notnull”,并设置默认值,避免where子句中“isnull”的判断。请勿在where子句中对“=”左侧进行函数、算术运算或其他表达式操作,否则系统将无法正确使用索引。使用尽可能少的MySQL函数。类似于Now()可以通过程序来实现和赋值,也可以通过适当建立冗余字段来间接替代一些功能。在where条件中使用or可能会导致索引失效。可以换成“unionall”或“union”(会过滤重复数据,效率比前者低),或者程序直接把数据分两次再合并,保证有效利用指数。不要使用select*,不是为了提高查询效率,主要是减少输出数据量,提高传输速度。避免类型转换。这里所说的“类型转换”是指where子句中的字段类型与传入的参数类型不一致时发生的类型转换。分页查询的优化。在页数较多的情况下,比如受limit10000,10影响的结果集为10010行,查询速度会变慢。推荐的方案是:先只查询主键selectidfromtablewhere..orderby..limit10000,10(请为搜索条件和排序创建索引),然后使用主键获取数据。统计相关查询。影响结果集往往是巨大的,有些SQL语句本身就很难优化。因此,应避免在业务高峰期进行统计相关的查询,或者只在从库进行统计查询。通过冗余数据结构可以保存部分统计数据。同时建议先将数据保存在内存和缓存(如redis)中,然后按照一定的策略写入数据库。不使用任何联表查询,通过分库分表实现负载均衡。随着数据量的增加,连接表的操作往往会导致结果集大量增加,无法从SQL优化层面解决问题。这时分库分表是解决数据库性能压力的最佳选择(分库分表的具体方案通常结合实际业务应用场景确定,此处略过).这里重点讨论如何更好的实现或者过渡到分库分表的分布式数据库架构。核心点是首先要去掉数据表之间的关联,即不使用外键,不使用连表查询。为了保证不进行连表操作,在设计数据库表结构时,需要设计适度冗余的字段,以达到不连表的目的。对于一些操作日志,支付记录等,设计一些字段来记录用户信息。我个人认为这不是多余的。毕竟用户信息经常变化,但是这种类似于操作日志的表确实需要记录用户操作过程中的信息。并且不需要在用户更新信息时同步更新。在实际开发中,为了实现不连接表的冗余字段,往往需要在原表更新数据的同时同步更新冗余字段的数据。如果应用层没有对数据表的操作进行适当的封装,这往往是一个比较棘手的问题,也不容易维护。当然,目前主流的应用框架一般都是使用orm来处理数据表,所以问题不大。相反,不连表其实可以提高开发效率,比如通过用户ID获取用户名。如果不连表,可以保证所有业务模块获取用户名的方式相同,调用相同的封装方法。这样在应用层添加缓存机制或者添加统一的业务逻辑都非常方便。同时,如果要对用户表进行分库分表,可以通过应用层程序简单顺利的实现。使用Innodb。关于Innodb和Myisam的比较就不多说了。Myisam的表级锁是一个致命的问题。考虑到MySQL已经默认使用Innodb作为数据库引擎,个人建议大部分情况下可以直接使用Innodb。其他引擎将不在这里详细讨论。使用缓存。1)尽可能实现程序中常用数据的缓存。目前主流的应用框架应该可以快速实现缓存需求。如果程序中没有实现数据缓存,启用数据库的查询缓存也是缓解数据库压力的方法之一。如果您确定要使用它,请记住定期清除碎片刷新查询缓存。服务器相关的MySQL服务配置优化和分布式架构实现,请根据实际应用场景和业务需求进行定制,非本文重点,不做深入探讨。
