查询慢是和表结构,语句,系统等相关的建索引等方法都可以改善表结构,另外如果返回数据量很大,当然会慢,所以你尽量查询相对有用的数据再就是查询语句了比如用in查询没有jion查询快,还有
between
改成
>
<会快再还有,用子查询也会慢很多,如果是一些很复杂的查询,可以改用存储过程会好点,有时用临时表会慢但,从海量数据中查询取数进行子查询又不如用临时表快,不同的问题用不同的解决方法,看你要哪种了,单看你的问题无法直接判断。不过,优化查询句是关键的了。
1 执行计划中明明有使用到索引,为什么执行还是这么慢?
2 执行计划中显示扫描行数为 644,为什么 slow log 中显示 100 多万行?
a 我们先看执行计划,选择的索引 “INDX_BIOM_ELOCK_TASK3(TASK_ID)”。结合 sql 来看,因为有 "ORDER BY TASK_ID DESC" 子句,排序通常很慢,如果使用了文件排序性能会更差,优化器选择这个索引避免了排序。
那为什么不选 possible_keys:INDX_BIOM_ELOCK_TASK 呢?原因也很简单,TASK_DATE 字段区分度太低了,走这个索引需要扫描的行数很大,而且还要进行额外的排序,优化器综合判断代价更大,所以就不选这个索引了。不过如果我们强制选择这个索引(用 force index 语法),会看到 SQL 执行速度更快少于 10s,那是因为优化器基于代价的原则并不等价于执行速度的快慢;
b 再看执行计划中的 type:index,"index" 代表 “全索引扫描”,其实和全表扫描差不多,只是扫描的时候是按照索引次序进行而不是行,主要优点就是避免了排序,但是开销仍然非常大。
Extra:Using where 也意味着扫描完索引后还需要回表进行筛选。一般来说,得保证 type 至少达到 range 级别,最好能达到 ref。
在第 2 点中提到的“慢日志记录Rows_examined: 1161559,看起来是全表扫描”,这里更正为“全索引扫描”,扫描行数确实等于表的行数;
c 关于执行计划中:“rows:644”,其实这个只是估算值,并不准确,我们分析慢 SQL 时判断准确的扫描行数应该以 slow log 中的 Rows_examined 为准。
4 优化建议:添加组合索引 IDX_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID)
优化过程:
TASK_DATE 字段存在索引,但是选择度很低,优化器不会走这个索引,建议后续可以删除这个索引:
select count(),count(distinct TASK_DATE) from T_BIOMA_ELOCK_TASK;+------------+---------------------------+| count() | count(distinct TASK_DATE) |+------------+---------------------------+| 1161559 | 223 |+------------+---------------------------+
在这个 sql 中 REL_DEVID 字段从命名上看选择度较高,通过下面 sql 来检验确实如此:
select count(),count(distinct REL_DEVID) from T_BIOMA_ELOCK_TASK;+----------+---------------------------+| count() | count(distinct REL_DEVID) |+----------+---------------------------+| 1161559 | 62235 |+----------+---------------------------+
由于有排序,所以得把 task_id 也加入到新建的索引中,REL_DEVID,task_id 组合选择度 100%:
select count(),count(distinct REL_DEVID,task_id) from T_BIOMA_ELOCK_TASK;+----------+-----------------------------------+| count() | count(distinct REL_DEVID,task_id) |+----------+-----------------------------------+| 1161559 | 1161559 |+----------+-----------------------------------+
在测试环境添加 REL_DEVID,TASK_ID 组合索引,测试 sql 性能:alter table T_BIOMA_ELOCK_TASK add index idx_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID);
添加索引后执行计划:
这里还要注意一点“隐式转换”:REL_DEVID 字段数据类型为 varchar,需要在 sql 中加引号:AND TREL_DEVID = 000000025xxx >> AND TREL_DEVID = '000000025xxx'
执行时间从 10s+ 降到 毫秒级别:
1 row in set (000 sec)
结论
一个典型的 order by 查询的优化,添加更合适的索引可以避免性能问题:执行计划使用索引并不意味着就能执行快。
问题
我们有一个 SQL,用于找到没有主键 / 唯一键的表,但是在 MySQL 57 上运行特别慢,怎么办?
实验
我们搭建一个 MySQL 57 的环境,此处省略搭建步骤。
写个简单的脚本,制造一批带主键和不带主键的表:
执行一下脚本:
现在执行以下 SQL 看看效果:
执行了 1680s,感觉是非常慢了。
现在用一下 DBA 三板斧,看看执行计划:
感觉有点惨,由于 information_schemacolumns 是元数据表,没有必要的统计信息。
那我们来 show warnings 看看 MySQL 改写后的 SQL:
我们格式化一下 SQL:
可以看到 MySQL 将
select from A where Ax not in (select x from B) //非关联子查询
转换成了
select from A where not exists (select 1 from B where Bx = ax) //关联子查询
如果我们自己是 MySQL,在执行非关联子查询时,可以使用很简单的策略:
select from A where Ax not in (select x from B where ) //非关联子查询:1 扫描 B 表中的所有记录,找到满足条件的记录,存放在临时表 C 中,建好索引2 扫描 A 表中的记录,与临时表 C 中的记录进行比对,直接在索引里比对,
而关联子查询就需要循环迭代:
select from A where not exists (select 1 from B where Bx = ax and ) //关联子查询扫描 A 表的每一条记录 rA: 扫描 B 表,找到其中的第一条满足 rA 条件的记录。
显然,关联子查询的扫描成本会高于非关联子查询。
我们希望 MySQL 能先"缓存"子查询的结果(缓存这一步叫物化,MATERIALIZATION),但MySQL 认为不缓存更快,我们就需要给予 MySQL 一定指导。
可以看到执行时间变成了 067s。
整理
我们诊断的关键点如下:
\1 对于 information_schema 中的元数据表,执行计划不能提供有效信息。
\2 通过查看 MySQL 改写后的 SQL,我们猜测了优化器发生了误判。
\3 我们增加了 hint,指导 MySQL 正确进行优化判断。
但目前我们的实验仅限于猜测,猜中了万事大吉,猜不中就无法做出好的诊断。
问题
我们有一个 SQL,用于找到没有主键 / 唯一键的表,但是在 MySQL 57 上运行特别慢,怎么办?
实验
我们搭建一个 MySQL 57 的环境,此处省略搭建步骤。
写个简单的脚本,制造一批带主键和不带主键的表:
执行一下脚本:
现在执行以下 SQL 看看效果:
执行了 1680s,感觉是非常慢了。
现在用一下 DBA 三板斧,看看执行计划:
感觉有点惨,由于 information_schemacolumns 是元数据表,没有必要的统计信息。
那我们来 show warnings 看看 MySQL 改写后的 SQL:
我们格式化一下 SQL:
可以看到 MySQL 将
select from A where Ax not in (select x from B) //非关联子查询
转换成了
select from A where not exists (select 1 from B where Bx = ax) //关联子查询
如果我们自己是 MySQL,在执行非关联子查询时,可以使用很简单的策略:
select from A where Ax not in (select x from B where ) //非关联子查询:1 扫描 B 表中的所有记录,找到满足条件的记录,存放在临时表 C 中,建好索引2 扫描 A 表中的记录,与临时表 C 中的记录进行比对,直接在索引里比对,
而关联子查询就需要循环迭代:
select from A where not exists (select 1 from B where Bx = ax and ) //关联子查询扫描 A 表的每一条记录 rA: 扫描 B 表,找到其中的第一条满足 rA 条件的记录。
显然,关联子查询的扫描成本会高于非关联子查询。
我们希望 MySQL 能先"缓存"子查询的结果(缓存这一步叫物化,MATERIALIZATION),但MySQL 认为不缓存更快,我们就需要给予 MySQL 一定指导。
可以看到执行时间变成了 067s。
整理
我们诊断的关键点如下:
\1 对于 information_schema 中的元数据表,执行计划不能提供有效信息。
\2 通过查看 MySQL 改写后的 SQL,我们猜测了优化器发生了误判。
\3 我们增加了 hint,指导 MySQL 正确进行优化判断。
但目前我们的实验仅限于猜测,猜中了万事大吉,猜不中就无法做出好的诊断。
原因有很多的。
主键约束。
当数据量达到百万以上的时候,你用主键去搜索某一条数据时速度是极快的。但当你不用主键去搜索的时候速度就降了几十倍甚至上百倍,这个是主键的好处。
索引。
当你的表字段设置有索引的时候,搜索速度比不创建索引要快几倍至几十倍。
sql语句不够优化。
在查询某数据的时候,能不用就尽量不用,想要哪个字段就查哪个,多余的不要,这样就能达到数据传输精简化,让查询速度也能快上许多。
多表联合查询。
在大数据量的时候这个多表查询尽量不用,毕竟是很耗内存的,宁愿用其他语言循环执行简单的 select 字段 from 表名 where 条件 这样的简单sql语句,这样也能加快速度。
数据库慢一般有三种情况
逐渐变慢
突然变慢
不定时变慢
第一种情况 逐渐变慢 要建立一个长期的监控机制 比如 写个shell脚本每天的忙时(通常 ~ etc )定时收集os neork db的信息 每个星期出report对收集到的信息进行分析 这些数据的积累 可以决定后期的优化决策 并且可以是DBA说服manager采用自己决策的重要数据 DBA的价值 就在每个星期的report中体现
第二种情况 突然变慢 也是最容易解决的 先从业务的角度看是DB的使用跟以前有何不同 然后做进一步判断 硬件/网络故障通常也会引起DB性能的突然下降
第一步: 察看DB/OS/NEORK的系统log 排除硬件/网络问题
第二步 察看数据库的等待事件 根据等待事件来判断可能出问题的环节 如果 没有等待事件 可以排除数据库的问题 如果有等待时间 根据不同的等待事件 来找引起这些事件的根源
比如latch free等跟SQL parse有关系的等待事件 OS的表现是CPU 的占用率高
db file scattered read等跟SQL disk read有关系的等待时间 OS的表现是iostat可以看到磁盘读写量增加
第三步: 察看os的信息 CPU/IO/MEMORY等
a Cpu 的占用率
CPU占用率与数据库性能不成反比 CPU占用率高 不能说明数据库性能慢 通常情况 一个优化很好 而且业务量确实很大的数据库 CPU的占用率都会高 而且会平均分布在每个进程上 反过来 CPU的占用率都会高也不代表数据库性能就好 要结合数据库的等待事件来判断CPU占用率高是否合理
如果某个进程的cpu占用高 肯定是这个进程有问题 如果 不是oracle的进程 可以让application察看是否程序有死循环等漏洞 如果 是oracle的进程 可以根据pid查找oracle数据字典看看这个进程的发起程序 正在执行的sql语句 以及等待事件 然后 不同情况使用不同的方法来解决
b IO
排除硬件的IO问题 数据库突然变慢 一般来说 都是一个或几个SQL语句引起的
如果IO很频繁 可以通过优化disk reads高的TOP SQL来解决 当然这也是解决IO问题的最笨也是最有效的办法
OS以及存储的配置也是影响IO的一个重要的原因
比如 最常见的HP unix下异步IO的问题 如果DBA GROUP没有MLOCK的权限 ORACLE是不使用AIO的 偏偏OS与DB的两方的admin如果配合不够好地话 这个配置就很容易给漏掉了
c Memory
第二种情况与memory的关系比较小 只要SGA区配置合理没有变化 一般来说 只要不是Application Memory leak 不会引起突然变慢的现象
第三种情况 不定时变慢 是最难解决的 现场出现的问题原因也是五花八门千奇百怪 最重要的是 出现慢的现象时 以最快的速度抓取到最多的信息以供分析 先写好抓取数据的shell 脚本 并在现象发生时及时按下回车键
一个例子
数据库突然变慢
背景: 一个新应用上线后 数据库突然变慢
第一步 调查新应用
据开发人员讲新应用访问的都是新建立的表 表的数据量很小 没有复杂的SQL查询
查询 v$sqlarea 分别按照disk_reads / buffer_gets / executions 排序 TOP SQL 中没有新应用的SQL 排除新应用数据库访问照成的性能问题
第二步 察看数据库log/ OS log
数据库log中可以看到大量的ORA 错误 以及大量的dump文件 分析dump文件(时间久了 没有dump文件可参考 具体细节没法描述下来 ) 发现是新应用通过dblink访问remote DB时生成的dump文件 应用开发人说没法修改 Oracle也没有相应的patch解决
OS log中没有错误信息
第三步 察看statspack report
从wait events中看到 Top event是 buffer busy waits db file parallel write 等于IO相关的等待事件
从buffer busy waits 的统计信息来看 是等待data block
还有些physical reads等信息与从前比没有太多的异常
Tablespace 的IO reads/writes也没有异常 但是wait明显增加
初步确定是IO问题
第四步 察看OS的信息
top 命令(输出为实验室数据 仅作格式参考)
load averages: : :
processes: sleeping zombie stopped on cpu
CPU states: % idle % user % kernel % iowait % swap
Memory: M real M free M swap in use M swap free
PID USERNAME THR PRI NICE SIZE RES STATE TIME CPU MAND
a K K cpu/ : % top
mpgj M K sleep : % view_server
当时现场数据显示 iowait 值与以前相比大很多 没有异常进程
sar –d (输出为实验室数据 仅作格式参考)
SunOS sc Generic_ sun u / /
: : device %busy avque r+w/s blks/s avwait avserv
sd
sd a
sd b
sd c
sd g
当时现场数据显示 放数据文件的设备 avwait avque blks/s值偏大
第五步 察看数据库的等待事件
一个大业务量的数据库如果性能不好的话 一般来说都会有大量的等待事件 上百个等待事件很常见 我通常会按照EVENT进行group
Select count() event from v$session_wait where event not in ( on timer pmon timer rdbms ipc message SQLNet message from client ) group by event order by desc;
输出结果显示最多的等待事件是buffer busy waits
进一步分析 找出等待的原因
Select count() p p p from v$session_wait where event = buffer busy waits group by p p p ;
在buffer busy waits等待事件中
P = file#
P = block#
P = id ( 此id对应为等待的原因)
按照p p p group是为了明确buffer busy waits的等待集中在哪些对象上
Metalink对buffer busy waits等待事件的描述有如下一段话
If P shows that the buffer busy wait is waiting for a block read to plete then the blocking session is likely to be waiting on an IO wait (eg: db file sequential read or db file scattered read for the same file# and block#
输出结果显示 等待分布在多个不同的对象上 等待原因为 waiting for a block read to plete 进一步分析为IO的问题
如果 buffer busy waits等待集中在某个对象上 说明有hot block 通过重新rebuild这个对象增加freelist来解决 RAC环境增加freelist group
通过以下SQL可以找到具体的object
Select owner segment_name segment_type from dba_extents where file_id=P and P beeen block_id and block_id+blocks;
P P 是上面v$session_wait查出的具体的值
第六步 明确原因 找出解决步骤
分析
磁盘的IO流量增加
磁盘的IO等待增加
DB的IO流量没有增加
DB的IO等待增加
由 可以推出 有数据库以外的IO访问磁盘
察看磁盘配置 该VG只存放了数据库数据文件和数据库系统文件 排除数据文件 产生IO的是数据库系统文件
数据库系统文件一般来说不会产生IO 有IO读写的地方只有log和dump文件
结论 ora 产生的大量core dump文件堵塞IO
解决办法
消除ora (应用不改的情况下 无法解决)
把dump目录指向别的VG
让oracle尽量少的去写core dump文件
background_core_dump = partial
lishixinzhi/Article/program/Oracle/201311/18969
1建立索引,尽可能把索引建立到你你经常比较的字段上,如select
a,b,c,d
from
a
where
索引字段=值,这个索引字段最好是数值型数据
2慢有更多情况,
情况1:远程查询,其实可能查询不慢,由于数据量大,传输过程慢
情况2:WHERE
后面的比较数据太多,比如
like
类的语句
情况3:需要哪个字段只取那个字段就行了,比如select
from
a与select
b,c,d
from
a速度是有差距的
3数据库定期维护,压缩,把不常用的数据备份后放入备份库里,查询时查备份库等
问题补充:
第一条:建立索引,怎么建立,我也听说过,但不知道怎么使用
答:每种数据建立索引的方法有差异,比如SQL
SERVER
2000中可对多个字段进行索引,比如SQL
SERVER2000中有命令
CREATE
INDEX
为给定表或视图创建索引。
只有表或视图的所有者才能为表创建索引。表或视图的所有者可以随时创建索引,无论表中是否有数据。可以通过指定限定的数据库名称,为另一个数据库中的表或视图创建索引。
语法
CREATE
[
UNIQUE
]
[
CLUSTERED
|
NONCLUSTERED
]
INDEX
index_name
ON
{
table
|
view
}
(
column
[
ASC
|
DESC
]
[
,n
]
)
[
WITH
<
index_option
>
[
,n]
]
[
ON
filegroup
]
<
index_option
>
::=
{
PAD_INDEX
|
FILLFACTOR
=
fillfactor
|
IGNORE_DUP_KEY
|
DROP_EXISTING
|
STATISTICS_NORECOMPUTE
|
SORT_IN_TEMPDB
}
第三条:数据库定期维护,压缩:怎么个压缩法?及时备份数据到备份库查询备份库,那查询时不是还慢吗?
答:这个有压缩工具,基本上每种数据库都有自己的压缩数据库的工具
数据库数据表的链接形式(是否链接表在另外的一个服务器上)、数据库打开的方式(是否独占 是否有人共享打开了)、是否 一个查询 过于复杂(多表的查询 可以先建立分表查询 然后 再对这些分表查询 进行合并查询速度会相对快一些)……
计算机的配置 是否有足够的 运算内存可供使用 等等……
总之 原因很多 要视你的工作环境来判断……
以上就是关于最近我的数据库(sql)查询速度很慢,这是什么原因全部的内容,包括:最近我的数据库(sql)查询速度很慢,这是什么原因、如何解决SQL查询速度太慢、如果mysql里面的数据过多,查询太慢怎么办等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)