zoukankan      html  css  js  c++  java
  • Sql 调优总结

    1前言

    Sql 语句调优对应用性能非常重要,看了几篇文章,总结了一下数据库优化的方法。

    2 数据库 Sql 优化

    1 对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

    关于索引请看我的这篇文章 https://www.cnblogs.com/mhq-martin/p/8184328.html

    SELECT sid
    FROM Student
    WHERE Gradeid=1

    执行时间:17.609s (多次执行,在17s左右徘徊)

    优化后:给Gradeid字段添加索引后

    执行时间为:11.377s(多次执行,在11s左右徘徊)

    备注:我们一般在什么字段上建索引?

    这是一个非常复杂的话题,需要对业务及数据充分分析后再能得出结果。主键及外键通常都要有索引,其它需要建索引的字段应满足以下条件:

    a、字段出现在查询条件中,并且查询条件可以使用索引;

    b、语句执行频率高,一天会有几千次以上;

    c、通过字段条件可筛选的记录集很小,那数据筛选比例是多少才适合?

    这个没有固定值,需要根据表数据量来评估,以下是经验公式,可用于快速评估:

    小表(记录数小于10000行的表):筛选比例<10%;

    大表:(筛选返回记录数)<(表总记录数*单条记录长度)/10000/16

    单条记录长度≈字段平均内容长度之和+字段数*2

    2 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描。

    select sid from Student where num is null

    最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库.

    备注、描述、评论之类的可以设置为 NULL,其他的,最好不要使用NULL。

    可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:

    select sid from Student where num = 0

    3 应尽量避免在 where 子句中使用 != 或 <> 操作符,否则引擎可能放弃使用索引而进行全表扫描。

    4 应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描。(用union all 代替)

    GRADE_ID字段有索引,QUESTION_TYPE没索引

    SELECT sid
    FROM Student
    WHERE Gradeid=15
    OR Gradetype=1

    优化方案:

    SELECT sid
    FROM Student
    WHERE Gradeid=15
    union all
    SELECT sid
    FROM Student
    WHERE Gradetype=1

    通过union all 方式,把有索引字段和非索引字段分开。索引字段就有效果了。

    5 in 和 not in 也要慎用,否则会导致全表扫描

    注:在mysql数据库中where 子句中对索引字段使用 in 和 not in操作符,引擎不会放弃使用索引。

    注:在mysql数据库中where 子句中对不是索引字段使用 in 和 not in操作符,会导致全表扫描。

    6 负向查询不能使用索引

    select name from user where id not in (1,3,4);

    应该修改为:

    select name from user where id in (2,5,6);

    7 前导模糊查询不能使用索引

    如:

    select name from user where name like '%zhangsan'

    非前导则可以:

    select name from user where name like 'zhangsan%'

    建议可以考虑使用 Lucene 等全文索引工具来代替频繁的模糊查询。

    8 数据区分不明显的不建议创建索引

    如 user 表中的性别字段,可以明显区分的才建议创建索引,如身份证等字段。

    9 在字段上进行计算不能命中索引

    select name from user where FROM_UNIXTIME(create_time) < CURDATE();

    应该修改为:

    select name from user where create_time < FROM_UNIXTIME(CURDATE());

    10 最左前缀问题

    如果给 user 表中的 username pwd 字段创建了复合索引那么使用以下SQL 都是可以命中索引:

    Java编程思想 数据库SQL语句的 优化总结

    但是使用

    select username from user where pwd ='axsedf1sd'

    是不能命中索引的。

    11 如果明确知道只有一条记录返回

    select name from user where username='zhangsan' limit 1

    可以提高效率,可以让数据库停止游标移动。

    12 不要让数据库帮我们做强制类型转换

    select name from user where telno=18722222222

    这样虽然可以查出数据,但是会导致全表扫描。

    需要修改为

    select name from user where telno='18722222222'

    13 如果需要进行 join 的字段两表的字段类型要相同

    不然也不会命中索引。

  • 相关阅读:

    list集合
    接口
    抽取对象的基本方法
    访问修饰符
    构造方法
    如何弹出一个对话框
    nginx反代配置
    TreeMap排序
    BeanPropertyRowMapper
  • 原文地址:https://www.cnblogs.com/mhq-martin/p/9317010.html
Copyright © 2011-2022 走看看