• mysql优化(中)

    普通类
    • 支持
    • 批判
    • 提问
    • 解释
    • 补充
    • 删除
    • 避免对列的操作

    任何对列的操作都可能导致全表扫描,这里所谓的操作包括数据库函数、计算表达式等
    等,查询时要尽可能将操作移至等式的右边,甚至去掉函数。
    例1:下列SQL条件语句中的列都建有恰当的索引,但30万行数据情况下执行速度却非
    常慢:
    select * from record where substrb(CardNo,1,4)='5378'(13秒)
    select * from record where amount/30< 1000(11秒)
    select * from record where to_char(ActionTime,'yyyymmdd')='19991201'(10秒)
    由于where子句中对列的任何操作结果都是在SQL运行时逐行计算得到的,因此它不得
    不进行表扫描,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就
    可以被SQL优化器优化,使用索引,避免表扫描,因此将SQL重写如下:
    select * from record where CardNo like '5378%'(< 1秒)
    select * from record where amount < 1000*30(< 1秒)
    select * from record where ActionTime= to_date ('19991201' ,'yyyymmdd')(< 1秒)
    差别是很明显的!

    • 避免不必要的类型转换

    需要注意的是,尽量避免潜在的数据类型转换。如将字符型数据与数值型数据比较,
    ORACLE会自动将字符型用to_number()函数进行转换,从而导致全表扫描。
    例2:表tab1中的列col1是字符型(char),则以下语句存在类型转换:
    select col1,col2 from tab1 where col1>10,
    应该写为: select col1,col2 from tab1 where col1>'10'。

    • 增加查询的范围限制

    增加查询的范围限制,避免全范围的搜索。
    例3:以下查询表record 中时间ActionTime小于2001年3月1日的数据:
    select * from record where ActionTime < to_date ('20010301' ,'yyyymm')
    查询计划表明,上面的查询对表进行全表扫描,如果我们知道表中的最早的数据为2001
    年1月1日,那么,可以增加一个最小时间,使查询在一个完整的范围之内。修改如下:select *
    from record where
    ActionTime < to_date ('20010301' ,'yyyymm')
    and ActionTime > to_date ('20010101' ,'yyyymm')
    后一种SQL语句将利用上ActionTime字段上的索引,从而提高查询效率。把'20010301'
    换成一个变量,根据取值的机率,可以有一半以上的机会提高效率。同理,对于大于某个值
    的查询,如果知道当前可能的最大值,也可以在Where子句中加上“AND 列名< MAX(最
    大值)”。

    • 尽量去掉"IN"、"OR"

    含有"IN"、"OR"的Where子句常会使用工作表,使索引失效;如果不产生大量重复值,
    可以考虑把子句拆开;拆开的子句中应该包含索引。
    例4: select count(*) from stuff where id_no in('0','1')(23秒)
    可以考虑将or子句分开:
    select count(*) from stuff where id_no='0'
    select count(*) from stuff where id_no='1'
    然后再做一个简单的加法,与原来的SQL语句相比,查询速度更快。

    • 尽量去掉"<>"

    尽量去掉"<>",避免全表扫描,如果数据是枚举值,且取值范围固定,则修改为"OR"
    方式。
    例5:
    UPDATE SERVICEINFO SET STATE=0 WHERE STATE<>0;
    以上语句由于其中包含了"<>",执行计划中用了全表扫描(TABLE ACCESS FULL) ,
    没有用到state字段上的索引。实际应用中,由于业务逻辑的限制,字段state为枚举值,只能
    等于0,1或2,而且,值等于=1,2的很少,因此可以去掉"<>",利用索引来提高效率。
    修改为:UPDATE SERVICEINFO SET STATE=0 WHERE STATE = 1 OR STATE = 2 。进一步的
    修改可以参考第4种方法。

    • 去掉Where 子句中的IS NULL 和IS NOT NULL

    Where字句中的IS NULL和IS NOT NULL将不会使用索引而是进行全表搜索,因此需要
    通过改变查询方式,分情况讨论等方法,去掉Where子句中的IS NULL和IS NOT NULL。

    • 索引提高数据分布不均匀时查询效率

    索引的选择性低,但数据的值分布差异很大时,仍然可以利用索引提高效率。A、数据
    分布不均匀的特殊情况下,选择性不高的索引也要创建。
    表ServiceInfo中数据量很大,假设有一百万行,其中有一个字段DisposalCourseFlag,取
    值范围为枚举值:[0,1,2,3,4,5,6,7]。按照前面说的索引建立的规则,“选择性不
    高的字段不应该建立索引,该字段只有8种取值,索引值的重复率很高,索引选择性明显很
    低,因此不建索引。然而,由于该字段上数据值的分布情况非常特殊,具体如下表:

    而且,常用的查询中,查询DisposalCourseFlag<6 的情况既多又频繁,毫无疑问,如果
    能够建立索引,并且被应用,那么将大大提高这种情况的查询效率。因此,我们需要在该字段上建立索引。

    • 标签:
    • 查询
    • 数据
    • select
    • 去掉
    • 字段
    • 优化
    • record
    • 扫描
    • mysql
    • state
    • 索引
    • actiontime
  • 加入的知识群:
    学习元评论 (0条)

    评论为空
    聪明如你,不妨在这 发表你的看法与心得 ~



    登录之后可以发表学习元评论
      
暂无内容~~
顶部