背景

每当交易高峰时期,可能会暴露一些平时无法发现的问题,机遇和挑战并存。下面聊聊最近解决的一个案例,因为执行计划走错导致慢查询,进而引发应用线程阻塞、线程池爆满,最后应用功能瘫痪。如何标本兼治的解决问题,需要很多思考。

问题分析

step1 应用瘫痪

用户反应某查询功能一直处于加载中,并出现错误提示。查看后台应用日志,调用远程查询服务出现大量超时。

step2 线程池爆满

通过jstack命令来分析查询服务jvm线程堆栈,发现设定的线程池已经满了,而且大部分线程阻塞在了数据库查询阶段(如下图),看来是有很多慢查询。

step3 慢查询的由来 - 错误执行计划

为何忽然出现这么多慢查询?我们来分析一下:

  1. SELECT no, time
  2. FROM tablename
  3. where no = :1
  4. and time >= to_date(:2, 'yyyy-mm-dd')
  5. and time < to_date(:3, 'yyyy-mm-dd')
  6. ORDER BY time DESC

注:条件字段(no、time)分别有索引(idx_no、idx_time)。

经过DBA帮助,分析上段sql的执行计划发现:

  • 有时数据库会走idx_no索引,查询很快

  • 有时会走idx_time索引,查询很慢

解决方案

既然数据库自动生成的执行计划有时会出问题,那么我们可以用hints语句指定当前sql走哪条索引,以固定执行计划。

下面以Oracle为例,添加hints:

  1. SELECT /*+ index(tablename IDX_NO) */ no, time
  2. FROM tablename
  3. where no = :1
  4. and time >= to_date(:2, 'yyyy-mm-dd')
  5. and time < to_date(:3, 'yyyy-mm-dd')
  6. ORDER BY time DESC

如果感觉在sql中添加不方便的话,oracle 10g以上版本提供了SQL Profile方式。

总结思考

这个问题应该一直有,为何在交易高峰时段才表现出来值得去研究。

    数据库:平时数据库压力较小,出现几个走错执行计划的慢查询,也只是让数据库压力比均值高出一小部分,性能未受影响。但是,高峰时段数据库本身就处于一个高负载状态,这时出现的慢查询无疑是雪上加霜,接近某个临界点时性能就明显下滑。

应用:慢查询会导致线程阻塞等待,一直占用线程池资源。我们知道,用户在点击查询按钮后发现一直加载,会不知觉多点几遍。这样的话,线程数量暴涨且大部分处于阻塞状态,线程池满了之后应用就会瘫痪掉,使其他正常的接口也无法正常工作。

综上所述,数据层的优化是治本,同时还要借助一些手段来保证不出现雪崩式性能下降。比如,在前台页面添加重复提交限制,尽量避免短时间内产生大量慢查询。

参考资料

Oracle Hints:https://docs.oracle.com/cd/B12037_01/server.101/b10752/hintsref.htm#5156

Oracle SQL Profile:https://docs.oracle.com/database/121/TGSQL/tgsql_profiles.htm#TGSQL596

SQL调优 - Hints指定索引 解决慢查询案例的更多相关文章

  1. MySQL索引和SQL调优手册

    MySQL索引 MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等.为了避免混乱,本文将只关注于BTree ...

  2. Oracle性能调优之虚拟索引用法简介

    本博客记录一下Oracle虚拟索引的用法,虚拟索引是定义在数据字典中的伪索引,可以说是伪列,没有修改的索引字段的.虚拟索引的目的模拟索引,不会增加存储空间的使用,有了虚拟索引,开发者使用执行计划的时候 ...

  3. 《高性能SQL调优精要与案例解析》一书谈主流关系库SQL调优(SQL TUNING或SQL优化)核心机制之——索引(index)

    继<高性能SQL调优精要与案例解析>一书谈SQL调优(SQL TUNING或SQL优化),我们今天就谈谈各主流关系库中,占据SQL调优技术和工作半壁江山的.最重要的核心机制之一——索引(i ...

  4. 你们一般都是怎么进行SQL调优的?MySQL在执行时是如何选择索引的?

    前言 过年回来的第二周了,终于有时间继续总结知识了.这次来看一下SQL调优的知识,这类问题基本上面试的时候都会被问到,无论你的岗位是后端,运维,测试等等. 像本文标题中的两个问题,就是我在实际面试过程 ...

  5. OCM_第十四天课程:Section6 —》数据库性能调优_各类索引 /调优工具使用/SQL 优化建议

    注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...

  6. SQL调优

    # 问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用 系统提交实际应用后,随着数据库中数据的增加,系 ...

  7. Oracle SQL 调优健康检查脚本

    Oracle SQL 调优健康检查脚本 我们关注数据库系统的性能,进行数据库调优的主要工作就是进行SQL的优化.良好的数据架构设计.配合应用系统中间件和写一手漂亮的SQL,是未来系统上线后不出现致命性 ...

  8. Oracle SQL调优记录

    目录 一.前言 二.注意点 三.Oracle执行计划 四.调优记录 @ 一.前言 本博客只记录工作中的一次oracle sql调优记录,因为数据量过多导致的查询缓慢,一方面是因为业务太过繁杂,关联了太 ...

  9. 《高性能SQL调优精要与案例解析》一书谈SQL调优(SQL TUNING或SQL优化)学习

    <高性能SQL调优精要与案例解析>一书上市发售以来,很多热心读者就该书内容及一些具体问题提出了疑问,因读者众多外加本人日常工作的繁忙 ,在这里就SQL调优学习进行讨论并对热点问题统一作答. ...

随机推荐

  1. thinkphp支持大小写url地址访问,不产生下划线

    from:http://www.111cn.net/phper/thinkPhp/57748.htm 一.在配置文件中开启了thinkphp的大小写识别功能,使链接大小写都可以正常访问: ‘URL_C ...

  2. 自定义Windows性能监视器

    Windows 性能监视器是一个很好用的自带监视工具,对于一些基本简单的监视需求可以轻松满足.本文主要总结了一下如何将自己应用中的一些性能数据暴露到性能监视器上方便管理. 什么?不知道什么是Windo ...

  3. Linux:多文件编辑

    多文件编辑 1.使用vim编辑多个文件 编辑多个文件有两种形式,一种是在进入vim前使用的参数就是多个文件.另一种就是进入vim后再编辑其他的文件. 同时创建两个新文件并编辑 $ vim 1.txt ...

  4. jenkins和docker 在docker里运行jenkins

    在docker里运行jenkins server. 文章来自:http://www.ciandcd.com文中的代码来自可以从github下载: https://github.com/ciandcd ...

  5. Spring AOP(注解方式)

    配置文件: xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org ...

  6. 利用模拟退火提高Kmeans的聚类精度

    http://www.cnblogs.com/LBSer/p/4605904.html Kmeans算法是一种非监督聚类算法,由于原理简单而在业界被广泛使用,一般在实践中遇到聚类问题往往会优先使用Km ...

  7. 《Web 开发基础》专题系列

      说在前头     Web的重要性我想不必我多说了,写这篇文章的目的主要是想分享一些我学习Web前端开发的知识积累,其中以JavaScript为主,比较适合新人看,也欢迎大牛们多多留言提提意见.   ...

  8. js中关于动态添加事件,不能使用循环变量的问题

    在编写事件的时候,我们难免会遇到以下这种情况:<!DOCTYPE html><html lang="en"><head> <meta ch ...

  9. 为何在font-family属性中设置多个值

    通常前端开发中会对body标签中设置font-family属性多个值,例如: body{padding:0;margin:0;font-size:12px;text-align:left;font-f ...

  10. cmdCreateViewTag

    start ).Y < grid.Curve.get_EndPoint().Y)                 {                     grid = gridTmp;    ...