1.EXPLAIN用于优化MySQL。我们一定要用好EXPLAIN来查看SQL的执行计划。下面举个简单的例子,标记(1,2,3,4,5)我们要关注的数据:类型列,连接类型。一个好的SQL语句至少要达到范围级别。避免所有级别的键列和使用的索引名称。如果未选择索引,则值为NULL。您可以使用强制索引key_len列、索引长度行列和要扫描的行数。该值是一个估计的额外列,详细说明。注意常见的不友好值有:Usingfilesort,Usingtemporary2.SQL语句中IN包含的值不要太多。MySQL对IN进行相应的优化,即将IN中的所有常量存储在一个数组中,并对这个数组进行排序。但是,如果值很大,消耗会比较大。又如:selectidfromtable_namewherenumin(1,2,3)对于连续值,可以用between代替in;或使用连接替换。3、SELECT语句必须指定字段名SELECT*增加了很多不必要的消耗(cpu、io、内存、网络带宽);增加使用覆盖索引的可能性;当表结构发生变化时,之前的break也需要更新。所以需要在select之后直接连接字段名。4.当只需要一条数据时,使用limit1,这是为了让EXPLAIN中的type列达到const类型。5.如果排序字段不使用索引,尽量少排序。如果oror两边有一个字段不是索引字段,其他条件也不是索引字段,则查询不会使用索引。很多情况下,用unionall或union(必要时)代替“或”会得到更好的结果七、尽量用unionall代替unionunion和unionall的区别主要是前者需要合并结果集独特的过滤操作,涉及到排序,增加大量CPU操作,增加资源消耗和延迟。当然,unionall的前提是两个结果集中没有重复的数据。8、不要使用ORDERBYRAND()selectidfrom`table_name`orderbyrand()limit1000;上面的sql语句可以优化为selectidfrom`table_name`t1join(selectrand()*(selectmax(id)from`table_name`)asnid)t2ont1。id>t2.nidlimit1000;九、区分in和exists,notin和notexistsselect*fromtableAwhereidin(selectidfromtableB)上面的sql语句等同于select*fromtableAwhereexists(select*fromtableB.id=tableA.id)in和exists的区别主要是驱动顺序的改变造成的(这是表现变化的关键)。如果存在,那么外表就是驱动表,首先被访问。如果是IN,那么先执行子查询。因此,IN适用于外观大而内表面小的场合;EXISTS适用于外观小而内表面大的情况。更多内容:面试题内容聚合关于notin和notexists,建议使用notexists,不仅是效率问题,notin可能会有逻辑问题。如何高效的写一个替换notexists的sql语句?原sql语句selectcolname...fromAtablewherea.idnotin(selectb.idfromBtable)高效sql语句selectcolname...fromAtableLeftjoinBtableonwherea.id=b.idwhereb.idisnull被取出结果集如图下图。表A中的数据不在表B中。十。使用合理的分页方式提高分页selectid,namefromtable_namelimit866613,20的效率,limit分页查询的增加会越来越慢。优化方法如下:可以取上一页最大行数的id,然后根据最大id限制下一页的起点。比如这一列,上一页最大的id是866612。SQL可以这样写:selectid,namefromtable_namewhereid>866612limit2011、分段查询在一些用户选择页面中,可能有些用户选择的时间范围过大,导致查询缓慢。主要原因是扫描线太多。这时候可以使用程序进行分段查询,循环遍历,合并结果显示。在下图所示的sql语句中,当扫描行数在百万以上时,可以使用分段查询。12、避免在where子句中判断字段的空值。null的判断会导致引擎放弃使用索引,进行全表扫描。十三。不建议使用%前缀模糊查询,如LIKE"%name"或LIKE"%name%"。这种查询会导致索引失效,进行全表扫描。但是你可以使用LIKE"name%"。那么如何查询%name%呢?如下图所示,虽然在secret字段中添加了索引,但并没有在explain结果中使用。那么如何解决这个问题,答案:使用全文索引在我们的查询中经常使用selectid,fnum,fdstfromtable_namewhereuser_namelike'%zhangsan%';。对于这样的语句,普通的索引是无法满足查询要求的。幸运的是,在MySQL中,有全文索引可以帮助我们。创建全文索引的sql语法为:ALTERTABLE`table_name`ADDFULLTEXTINDEX`idx_user_name`(`user_name`);使用全文索引的sql语句为:selectid,fnum,fdstfromtable_namewherematch(user_name)against('zhangsan'inbooleanmode);注意:当需要创建全文索引前,请联系DBA确定是否可以创建。同时需要注意的是,查询语句的写法与普通索引的写法不同。第十四,避免对where子句中的字段进行表达式操作。引擎放弃使用索引,建议改为selectuser_id,user_projectfromtable_namewhereage=36/2;十五、避免隐式类型转换。当where子句中列字段的类型与传入参数的类型不一致时,建议先判断类型转换。其中十六的参数类型。对于联合索引,必须遵循最左前缀规则。例如,索引包含字段id、name和school。可以直接使用id字段,也可以使用id,name,name的顺序,学校不能使用这个索引。因此,在创建联合索引时,一定要注意索引字段的顺序。常用的查询字段放在顶部。十七、必要时可以使用forceindex强制查询使用某个索引。有时MySQL优化器会使用它认为合适的索引。去检索sql语句,但是它可能使用的索引不是我们想要的。这时候可以使用forceindex强制优化器使用我们做的索引。十八、注意范围查询语句对于联合索引,如果有范围查询,比如between,>,<等条件,会导致后面的索引字段失效。19.关于JOIN优化LEFTJOINA表为驱动表INNERJOINMySQL会自动找数据少的表作为驱动表RIGHTJOINB表为驱动表注意:MySQL中没有fulljoin,你可以使用以下方法解决select*fromAleftjoinBonB.name=A.namewhereB.nameisnullunionallselect*fromB;(1)尽量使用innerjoin,避免leftjoin参与联合查询。至少有两张桌子,通常大小不一。如果连接方式是innerjoin,在没有其他过滤条件的情况下,MySQL会自动选择小表作为驱动表,而leftjoin在驱动表的选择上遵循从左向右驱动的原则,即即,驱动器表的leftjoin左侧的表名。为什么代码规范要求SQL语句不要加入太多?(2)合理使用索引驱动表的索引字段作为on的limit字段。(3)用小表驱动大表从示意图中可以直观看出,如果可以减少驱动表,则可以减少嵌套循环的循环次数,从而减少IO总量和CPU操作数。(4)STRAIGHT_JOINinnerjoin的巧妙使用mysql选择作为驱动表,但在某些特殊情况下,需要选择另外一张表作为驱动表,比如有groupby,orderby等时。”使用文件排序”和“使用临时”。STRAIGHT_JOIN强制连接顺序,STRAIGHT_JOIN左边的表名是驱动表,右边是从动表。使用STRAIGHT_JOIN的前提是查询是innerjoin,即内连接。其他链接不建议使用STRAIGHT_JOIN,否则可能导致查询结果不准确。这种方法有时可以减少3倍的时间。这里仅提供上述优化方案,当然还有其他的优化方式,大家可以自行探索尝试。
