1.一些常见的SQL做法(1)否定条件查询不能使用索引select*fromorderwherestatus!=0andstauts!=1notin/notexists不是一个好习惯可以优化为inQuery:select*fromorderwheredesclike'XX%'(2)前导模糊查询不能使用索引select*fromorderwheredesclike'%XX'代替前导模糊查询:select*fromorderwheredesclike'XX%'(3)区分度不大的数据字段不应该使用indexselect*fromuserwheresex=1原因:性别只有男和女,每次过滤出来的数据很小,不适合使用索引。根据经验,当可以过滤80%的数据时,可以使用索引。对于订单状态,如果状态值很少,不适合使用索引。如果状态值很多,可以过滤的数据量很大,就应该建立索引。(4)属性上的计算不能***索引select*fromorderwhereYEAR(date)<='2017'即使在date上建立索引,也会扫描全表,可以优化value计算:select*fromorderwheredate<=CURDATE()or:select*fromorderwheredate<='2017-01-01'二、不为人知的SQL实践(5)如果大部分业务是单条查询,使用Hash索引性能更好,比如用户中心select*fromuserwhereuid=?select*fromuserwherelogin_name=?原因:B-Tree索引的时间复杂度为O(log(n))Hash索引的时间复杂度为O(1)(6)允许空列,查询有潜在的陷阱。单列索引不存在。null值,复合索引不存储所有的null值,如果列允许null,可能会得到一个“意外”的结果集select*fromuserwherename!='shenjian'如果name允许null,则索引不存储null值,这些记录不会包含在结果集中。所以,请使用非空约束和默认值。(7)复合索引最左边的前缀不是值。SQL语句的where顺序必须和组合索引一致。用户中心建立了复合索引(login_name,passwd)select*fromuserwherelogin_name=?andpasswd=?select*fromuserwherepasswd=?andlogin_name=?***索引可以select*fromuserwherelogin_name=吗?也可以***索引,满足复合索引的最左前缀select*fromuserwherepasswd=?不能***索引,不满足复合索引的最左前缀(8)用ENUM代替字符字符串ENUM存储TINYINT。不要在枚举中使用“中国”、“北京”、“技术部”等字符串。字符串空间大,效率低。3.小众但有用的SQL实践(9)如果知道只返回一个结果,limit1可以提高效率select*fromuserwherelogin_name=?可以优化为:select*fromuserwherelogin_name=?不知道,说清楚,让它主动停止游标移动(10)把计算放在业务层而不是数据库层,除了节省数据CPU,还有意想不到的查询缓存优化效果select*fromorderwheredate<=CURDATE()这不是一个好的SQL实践,应该优化为:$curDate=date('Y-m-d');$res=mysql_query('select*fromorderwheredate<=$curDate');原因:多次调用释放了数据库的CPU,传入的SQL都是一样的,才可以使用querycache。(11)强制类型转换会扫描全表select*fromuserwherephone=13800001234你觉得会***phone索引吗?大错特错,这个说法怎么改?最后再补充一句,不要使用select*(潜台词,文章的SQL不合格=_=),只返回需要的列,这样可以大大节省数据传输量和数据库的内存占用。【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文
