• mysql优化(下)

    普通类
    • 支持
    • 批判
    • 提问
    • 解释
    • 补充
    • 删除
    • 分解复杂查询,用常量代替变量

    对于复杂的Where条件组合,Where中含有多个带索引的字段,考虑用IF语句分情况进
    行讨论;同时,去掉不必要的外来参数条件,减低复杂度,以便在不同情况下用不同字段上
    的索引。
    继续上面9的例子,对于包含
    Where (DisposalCourseFlag < v_DisPosalCourseFlag) or (v_DisPosalCourseFlag is null) and
    ....的查询,(这里v_DisPosalCourseFlag为一个输入变量,取值范围可能为[NULL,0,1,2,
    3,4,5,6,7]),可以考虑分情况用IF语句进行讨论,类似:
    IF v_DisPosalCourseFlag =1 THEN
    Where DisposalCourseFlag = 1 and ....
    ELSIF v_DisPosalCourseFlag =2 THEN
    Where DisposalCourseFlag = 2 and ....

    • like 子句尽量前端匹配

    因为like参数使用的非常频繁,因此如果能够对like子句使用索引,将很高的提高查询的
    效率。
    例6:select * from city where name like ‘%S%’
    以上查询的执行计划用了全表扫描(TABLE ACCESS FULL),如果能够修改为:
    select * from city where name like ‘S%’
    那么查询的执行计划将会变成(INDEX RANGE SCAN),成功的利用了name字段的索
    引。这意味着Oracle SQL优化器会识别出用于索引的like子句,只要该查询的匹配端是具体
    值。因此我们在做like查询时,应该尽量使查询的匹配端是具体值,即使用like ‘S%’。

    • 用Case 语句合并多重扫描

    我们常常必须基于多组数据表计算不同的聚集。例如下例通过三个独立查询:
    例8:1)select count(*) from emp where sal<1000;
    2)select count(*) from emp where sal between 1000 and 5000;
    3)select count(*) from emp where sal>5000;
    这样我们需要进行三次全表查询,但是如果我们使用case语句:
    select
    count (sale when sal <1000
    then 1 else null end) count_poor,
    count (sale when between 1000 and 5000
    then 1 else null end) count_blue_collar,
    count (sale when sal >5000
    then 1 else null end) count_poor
    from emp;
    这样查询的结果一样,但是执行计划只进行了一次全表查询。

    • 使用nls_date_format


    select * from record where to_char(ActionTime,'mm')='12'
    这个查询的执行计划将是全表查询,如果我们改变nls_date_format,
    SQL>alert session set nls_date_formate=’MM’;
    现在重新修改上面的查询:
    select * from record where ActionTime='12'
    这样就能使用actiontime上的索引了,它的执行计划将是(INDEX RANGE SCAN)。

    • 使用基于函数的索引

    前面谈到任何对列的操作都可能导致全表扫描,例如:
    select * from emp where substr(ename,1,2)=’SM’;
    但是这种查询在客服系统又经常使用,我们可以创建一个带有substr函数的基于函数的
    索引,
    create index emp_ename_substr on eemp ( substr(ename,1,2) );
    这样在执行上面的查询语句时,这个基于函数的索引将排上用场,执行计划将是
    (INDEX RANGE SCAN)。

    • 基于函数的索引要求等式匹配

    上面的例子中,我们创建了基于函数的索引,但是如果执行下面的查询:
    select * from emp where substr(ename,1,1)=’S’
    得到的执行计划将还是(TABLE ACCESS FULL),因为只有当数据列能够等式匹配时,
    基于函数的索引才能生效,这样对于这种索引的计划和维护的要求都很高。请注意,向表中
    添加索引是非常危险的操作,因为这将导致许多查询执行计划的变更。然而,如果我们使用
    基于函数的索引就不会产生这样的问题,因为Oracle只有在查询使用了匹配的内置函数时才
    会使用这种类型的索引。

    • 使用分区索引

    在用分析命令对分区索引进行分析时,每一个分区的数据值的范围信息会放入Oracle的
    数据字典中。Oracle可以利用这个信息来提取出那些只与SQL查询相关的数据分区。
    例如,假设你已经定义了一个分区索引,并且某个SQL语句需要在一个索引分区中进行
    一次索引扫描。Oracle会仅仅访问这个索引分区,而且会在这个分区上调用一个此索引范围
    的快速全扫描。因为不需要访问整个索引,所以提高了查询的速度。

    • 使用位图索引

    位图索引可以从本质上提高使用了小于1000个唯一数据值的数据列的查询速度,因为在
    位图索引中进行的检索是在RAM中完成的,而且也总是比传统的B树索引的速度要快。对于
    那些少于1000个唯一数据值的数据列建立位图索引,可以使执行效率更快。

    • 决定使用全表扫描还是使用索引

    和所有的秘笈一样,最后一招都会又回到起点,最后我们来讨论一下是否需要建立索引,
    也许进行全表扫描更快。在大多数情况下,全表扫描可能会导致更多的物理磁盘输入输出,
    但是全表扫描有时又可能会因为高度并行化的存在而执行的更快。如果查询的表完全没有顺
    序,那么一个要返回记录数小于10%的查询可能会读取表中大部分的数据块,这样使用索引
    会使查询效率提高很多。但是如果表非常有顺序,那么如果查询的记录数大于40%时,可能
    使用全表扫描更快。因此,有一个索引范围扫描的总体原则是:
    1)对于原始排序的表仅读取少于表记录数40%的查询应该使用索引范围扫描。反之,
    读取记录数目多于表记录数的40%的查询应该使用全表扫描。
    2)对于未排序的表仅读取少于表记录数7%的查询应该使用索引范围扫描。反之,
    读取记录数目多于表记录数的7%的查询应该使用全表扫描。

    • 总结


    以上的招式,是完全可以相互结合同时运用的。而且各种方法之间相互影响,紧密联系。
    这种联系既存在一致性,也可能带来冲突,当冲突发生时,需要根据实际情况进行选择,没
    有固定的模式。最后决定SQL优化功力的因素就是对ORACLE内功的掌握程度了。
    另外,值得注意的是:随着时间的推移和数据的累计与变化,ORACLE对SQL语句的执
    行计划也会改变,比如:基于代价的优化方法,随着数据量的增大,优化器可能错误的不选
    择索引而采用全表扫描。这种情况可能是因为统计信息已经过时,在数据量变化很大后没有
    及时分析表;但如果对表进行分析之后,仍然没有用上合理的索引,那么就有必要对SQL
    语句用HINT提示,强制用合理的索引。但这种HINT提示也不能滥用,因为这种方法过于复
    杂,缺乏通用性和应变能力,同时也增加了维护上的代价;相对来说,基于函数右移、去掉
    “IN ,OR ,<> ,IS NOT NULL ”、分解复杂的SQL语句等等方法,却是“放之四海皆
    准”的,可以放心大胆的使用。
    同时,优化也不是“一劳永逸”的,必须随着情况的改变进行相应的调整。当数据库设
    计发生变化,包括更改表结构:字段和索引的增加、删除或改名等;业务逻辑发生变化:如
    查询方式、取值范围发生改变等等。在这种情况下,也必须对原有的优化进行调整,以适应
    效率上的需求。

    • 标签:
    • 查询
    • 进行
    • 数据
    • 使用
    • select
    • 这种
    • 优化
    • 扫描
    • 函数
    • 语句
    • mysql
    • 索引
  • 加入的知识群:
    学习元评论 (0条)

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



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