zoukankan      html  css  js  c++  java
  • SQL优化

      

    1、查询SQL尽量不要使用select *,而是select具体字段。

    理由:

    • 只取需要的字段,节省资源、减少网络开销。

    • select * 进行查询时,很可能就不会使用到覆盖索引了,就会造成回表查询。

    2、如果知道查询结果只有一条或者只要最大/最小一条记录,建议用limit 1

    理由:

    • 加上limit 1后,只要找到了对应的一条记录,就不会继续向下扫描了,效率将会大大提高。

    • 当然,如果name是唯一索引的话,是不必要加上limit 1了,因为limit的存在主要就是为了防止全表扫描,从而提高性能,如果一个语句本身可以预知不用全表扫描,有没有limit ,性能的差别并不大。

    3、应尽量避免在where子句中使用or来连接条件

    应当使用两条SQL语句。在程序中控制。

    理由:

    • 使用or可能会使索引失效,从而全表扫描。

    对于or+没有索引的age这种情况,假设它走了userId的索引,但是走到age查询条件时,它还得全表扫描,也就是需要三步过程:全表扫描+索引扫描+合并 如果它一开始就走全表扫描,直接一遍扫描就完事。mysql是有优化器的,处于效率与成本考虑,遇到or条件,索引可能失效,看起来也合情合理。

    4、优化limit分页

    select * from articles where id >(select id from articles limit 170500,1) limit 500

    这种方法的好处是首先通过id索引快速定位到了分页数据的起始位置(避免了全文检索),并且用limit 方法快速获取了从起始位置往后的500个数据。

    最优:select * from articles where id between (select id from articles limit 170000,1) and (select id from articles limit 170500,1)

    between and的方法相当于也是利于id索引的优势,但是同时定位了分页的起始和终止的位置,截取了中间的信息,因此速度会更快.

    5:尽量避免在索引列上使用mysql的内置函数

    会导致索引失效

    6:应尽量避免在where子句中对字段进行表达式操作,这将导致系统放弃使用索引而进行全表扫

    7:Inner join 、left join、right join,优先使用Inner join,如果是left join,左边表结果尽量小

    1. Inner join 内连接,在两张表进行连接查询时,只保留两张表中完全匹配的结果集
    2. left join 在两张表进行连接查询时,会返回左表所有的行,即使在右表中没有匹配的记录。
    3. right join 在两张表进行连接查询时,会返回右表所有的行,即使在左表中没有匹配的记录。

    都满足SQL需求的前提下,推荐优先使用Inner join(内连接),如果要使用left join,左边表数据结果尽量小,如果有条件的尽量放到左边处理。

    8:使用exists

    假设表A表示某企业的员工表,表B表示部门表,查询所有部门的所有员工,很容易有以下SQL:

    1. select * from A where deptId in (select deptId from B);

    这样写等价于:

    先查询部门表B

    select deptId from B

    再由部门deptId,查询A的员工

    select * from A where A.deptId = B.deptId

    可以抽象成这样的一个循环:

    1. List<> resultSet ;

    2. for(int i=0;i<B.length;i++) {

    3. for(int j=0;j<A.length;j++) {

    4. if(A[i].id==B[j].id) {

    5. resultSet.add(A[i]);

    6. break;

    7. }

    8. }

    9. }

    显然,除了使用in,我们也可以用exists实现一样的查询功能,如下:

    1. select * from A where exists (select 1 from B where A.deptId = B.deptId);

    因为exists查询的理解就是,先执行主查询,获得数据后,再放到子查询中做条件验证,根据验证结果(true或者false),来决定主查询的数据结果是否得意保留。

    那么,这样写就等价于:

    select * from A,先从A表做循环

    select * from B where A.deptId = B.deptId,再从B表做循环.

    同理,可以抽象成这样一个循环:

    1. List<> resultSet ;

    2. for(int i=0;i<A.length;i++) {

    3. for(int j=0;j<B.length;j++) {

    4. if(A[i].deptId==B[j].deptId) {

    5. resultSet.add(A[i]);

    6. break;

    7. }

    8. }

    9. }

    数据库最费劲的就是跟程序链接释放。假设链接了两次,每次做上百万次的数据集查询,查完就走,这样就只做了两次;相反建立了上百万次链接,申请链接释放反复重复,这样系统就受不了了。即mysql优化原则,就是小表驱动大表,小的数据集驱动大的数据集,从而让性能更优。

    因此,我们要选择最外层循环小的,也就是,如果B的数据量小于A,适合使用in,如果B的数据量大于A,即适合选择exist

  • 相关阅读:
    vue系列---响应式原理实现及Observer源码解析(七)
    学习Lowdb小型本地JSON数据库
    渐进式web应用开发---Service Worker 与页面通信(七)
    webpack4核心模块tapable源码解析
    electron 创建托盘应用
    运维堡垒机开发
    使用Supervisord软件管理go服务进程
    安装Harbor之http版本
    Ubuntu 18 LTS netplan 网络配置
    用GO开发企业级分布式云存储系统
  • 原文地址:https://www.cnblogs.com/bulrush/p/12573958.html
Copyright © 2011-2022 走看看