12 MySQL常见优化

操作符优化

1): <> 操作符(不等于)
优化原因:
    不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。 

优化方法:
    a):  用其它相同功能的操作运算代替,如 a<>0 改为 a>0 or a<0   a<>'' 改为 a>'' 
    b):  尽量便面使用 != 操作符,如 c != '' 应写成  c > ''
2): LIKE优化
优化方法:
    a):  LIKE '名称%'-----可以使用到索引,可以使用
    b):  LIKE '%名称%'----不会使用索引,尽量避免使用,只能在语句上进行优化        
            原SQL: Select object_id,object_type,object_name from t1 
                        where object_name like '%ABC%';

            改写后的SQL:Select object_id ,object_type,object_name from t1 
                            Where object_name in
                                (select object_name from t1 where object_name like '%ABC%');
    c):  LIKE '%名称'-----不会使用到索引,应优化
             1:  首先,在查询的列建立反向索引
                    cerate index 索引名称 on 表名(reverse(列名));
             2:  查询语句如下: 
                    select count(*) from emp where reverse(列名) like reverse('%名称');

    用全文搜索搜索文本数据,取代like搜索
        全文搜索始终优于like搜索:
            (1)全文搜索让你可以实现like不能完成的复杂搜索,如搜索一个单词或一个短语,搜索一个与另一个单词或短语相近的单词或短语,或者是搜索同义词;
            (2)实现全文搜索比实现like搜索更容易(特别是复杂的搜索); 

in,not in,exists与not exists

in和exists
    in是把外表和内表作hash连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询,一直以来认为exists比in效率高的说法是不准确的。
    如果查询的两个表大小相当,那么用in和exists差别不大;如果两个表中一个较小一个较大,则子查询表大的用exists,子查询表小的用in;
    
    例如:表A(小表),表B(大表)
        select * from A where cc in(select cc from B)  -->效率低,用到了A表上cc列的索引;
        select * from A where exists(select cc from B where cc=A.cc)  -->效率高,用到了B表上cc列的索引。

    相反的:    
        select * from B where cc in(select cc from A)  -->效率高,用到了B表上cc列的索引
        select * from B where exists(select cc from A where cc=B.cc)  -->效率低,用到了A表上cc列的索引。
Not IN 不走索引的是绝对不能用的,可以用NOT EXISTS 代替

where子句优化

1): 第一个原则:在where子句中应把最具限制性的条件放在最前面。
    在下面两条select语句中:
        select * from table1 where field1<=10000 and field1>=0;
        select * from table1 where field1>=0 and field1<=10000;
        如果数据表中的数据field1都>=0,则第一条select语句要比第二条select语句效率高的多,
        因为第二条select语句的第一个条件耗费了大量的系统资源。
2): 第二个原则:where子句中字段的顺序应和索引中字段顺序一致。
    在下面的select语句中:
        select * from tab where a=… and b=… and c=…;
        若有索引index(a,b,c),则where子句中字段的顺序应和索引中字段顺序一致。
3): 应尽量避免在 where 子句中使用 or 来连接条件,
如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如:   
    select id from t where num=10 or Name = 'admin'   
    可以这样查询:   
    select id from t where num = 10   
    union all   
    select id from t where Name = 'admin'  
4): 应尽量避免在 where 子句中等号的左端对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
    select id from t where num/2 = 100   
    应改为:   
    select id from t where num = 100*2
5): 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,
否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。(不需要完全一致。最左前缀原则。)   
eg:

以下假设在field1上有唯一索引I1,在field2上有非唯一索引I2。

      1): 
        a):
            select field3,field4 from tb where field1='sdf' 快
            select * from tb where field1='sdf' 慢,
            因为后者在索引扫描后要多一步ROWID表访问。

        b):
            select field3,field4 from tb where field1>='sdf' 快
            select field3,field4 from tb where field1>'sdf' 慢
            因为前者可以迅速定位索引。

        c):
            select field3,field4 from tb where field2 like 'R%' 快
            select field3,field4 from tb where field2 like '%R' 慢,
            因为后者不使用索引。

    2) 使用函数如:
            select field3,field4 from tb where upper(field2)='RMN'不使用索引。
            如果一个表有两万条记录,建议在WHERE子句中不使用函数;
            如果一个表有五万条以上记录,在WHERE子句中严格禁止使用函数!两万条记录以下没有限制。 

SQL语句注意事项

1. 在查询中不要使用select *
为什么不能使用,地球人都知道,但是很多人都习惯这样用,要明白能省就省,而且这样查询数据库不能利用“覆盖索引”了
2. 尽量写WHERE子句
尽量不要写没有WHERE的SQL语句
3. 注意SELECT INTO后的WHERE子句
因为SELECT INTO把数据插入到临时表,这个过程会锁定一些系统表,如果这个WHERE子句返回的数据过多或者速度太慢,会造成系统表长期锁定,诸塞其他进程。
4. 对于聚合查询,可以用HAVING子句进一步限定返回的行
5. 避免使用临时表
(1)除非却有需要,否则应尽量避免使用临时表,相反,可以使用表变量代替;
(2)大多数时候(99%),表变量驻扎在内存中,因此速度比临时表更快,临时表驻扎在TempDb数据库中,因此临时表上的操作需要跨数据库通信,速度自然慢。
6. 减少访问数据库的次数:
程序设计中最好将一些常用的全局变量表放在内存中或者用其他的方式减少数据库的访问次数
7. 尽量少做重复的工作
尽量减少无效工作,但是这一点的侧重点在客户端程序,需要注意的如下:
    A、控制同一语句的多次执行,特别是一些基础数据的多次执行是很多程序员很少注意的
    B、减少多次的数据转换,也许需要数据转换是设计的问题,但是减少次数是程序员可以做到的。
    C、杜绝不必要的子查询和连接表,子查询在执行计划一般解释成外连接,多余的连接表带来额外的开销。
    D、合并对同一表同一条件的多次UPDATE,比如
        UPDATE EMPLOYEE SET FNAME='HAIWER' WHERE EMP_ID='VPA30890F'
        UPDATE EMPLOYEE SET LNAME='YANG' WHERE EMP_ID='VPA30890F'
        这两个语句应该合并成以下一个语句
        UPDATE EMPLOYEE SET FNAME='HAIWER',LNAME='YANG'
        WHERE EMP_ID=' VPA30890F'
    E、UPDATE操作不要拆成DELETE操作+INSERT操作的形式,虽然功能相同,但是性能差别是很大的。
    F、不要写一些没有意义的查询,比如
        SELECT * FROM EMPLOYEE WHERE 1=2 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350