sql性能调优

show profiles 查看最近几次sql执行情况
show variables like ‘%profiling%’ 查看profile是否开启 set profiling=1 开启
show profile cpu,block io,MEMORY for query 15(query_id)查看cpu,io,memory开销
#6.日常开发需注意的结论。(出现下面四种需要优化sql)
①converting HEAP to MyISAM:查询结果太大,内存不够,数据往磁盘上搬了。
②Creating tmp table:创建临时表。先拷贝数据到临时表,用完后再删除临时表。
③Copying to tmp table on disk:把内存中临时表复制到磁盘上,危险!!!
④locked。

show engines:查看所有的数据库引擎

索引
索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上
1.虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为
更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为
更新所带来的键值变化后的索引信息。
2.实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间
的。
MySQL 使用的是Btree 索引。
B-树的关键字和记录是放在一起的,叶子节点可以看作外部节点,不包含任何信息;
B+树的非叶子节点中只有关键字和指向下一个节点的索引,记录只放在叶子节点中
B+非叶子节点只不存储真实的数据,只存储指引搜索方向的数据项

B+树比B-树更适合实际应用中操作系统的文件索引和数据库索引
B+树的磁盘读写代价更低
B+树的查询效率更加稳定

每个Mysql 的表只能有一个聚簇索引
‘聚簇’表示数据行和相邻的键值聚簇的存储在一起。

下面的情况适合索引
 主键自动建立唯一索引;
 频繁作为查询条件的字段应该创建索引
 查询中与其它表关联的字段,外键关系建立索引
 单键/组合索引的选择问题, 组合索引性价比更高
 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
 查询中统计或者分组字段

不适合创建索引的情况
 表记录太少
 经常增删改的表或者字段
 Where 条件里用不到的字段不创建索引
 过滤性不好的不适合建索引

explain sql
1.id 号每个号码,表示一趟独立的查询。一个sql 的查询趟数越少越好。

2.select_type
代表查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询。
SIMPLE 简单的select 查询,查询中不包含子查询或者UNION
PRIMARY 查询中若包含任何复杂的子部分,最外层查询则被标记为Primary
DERIVED 在FROM 列表中包含的子查询被标记为DERIVED(衍生)
MySQL 会递归执行这些子查询, 把结果放在临时表里。
SUBQUERY 在SELECT或WHERE列表中包含了子查询
DEPEDENT SUBQUERY 在SELECT或WHERE列表中包含了子查询,子查询基于外层
UNCACHEABLE SUBQUERY 无法使用缓存的子查询
UNION 若第二个SELECT出现在UNION之后,则被标记为UNION;
若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
UNION RESULT 从UNION表获取结果的SELECT

3.type
type 是查询的访问类型。是较为重要的一个指标,结果值从最好到最坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index >ALL
一般来说,得保证查询至少达到range 级别,最好能达到ref。
(1)system
表只有一行记录(等于系统表),这是const 类型的特列,平时不会出现,这个也可以忽略不计
(2)const
表示通过索引一次就找到了,const 用于比较primary key 或者unique 索引。因为只匹配一行数据,所以很快
如将主键置于where 列表中,MySQL 就能将该查询转换为一个常量。
(3)eq_ref
唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。
(4)ref
非唯一性索引扫描,返回匹配某个单独值的所有行.本质上也是一种索引访问,它返回所有匹配某个单独值的行,
然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。
(5)ref_or_null
对于某个字段既需要关联条件,也需要null 值得情况下。查询优化器会选择用ref_or_null 连接查询。
(6)index_merge
在查询过程中需要多个索引组合使用,通常出现在有or 的关键字的sql 中。
(7)unique_subquery
该联接类型类似于index_subquery。子查询中的唯一索引。
(8)index_subquery
利用索引来关联子查询,不再全表扫描。
(9)range
只检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引一般就是在你的where 语句中出现
了between、<、>、in 等的查询这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而
结束语另一点,不用扫描全部索引。
(10)index
出现index是sql使用了索引但是没用通过索引进行过滤,一般是使用了覆盖索引或者是利用索引进行了排序分组。
(11)all
Full Table Scan,将遍历全表以找到匹配的行。

4.possible_keys
显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引将被列出,但不一
定被查询实际使用。

5.key
实际使用的索引。如果为NULL,则没有使用索引。

6.key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。key_len 字段能够帮你检查是否充分的
利用上了索引。ken_len 越长,说明索引使用的越充分。

7.ref
显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。

8.rows
rows 列显示MySQL 认为它执行查询时必须检查的行数。越少越好!

9.Extra
其他的额外重要的信息。
(1)Using filesort
说明mysql 会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL 中无法利用索引
完成的排序操作称为“文件排序”。
(2)Using temporary
使了用临时表保存中间结果,MySQL 在对查询结果排序时使用临时表。常见于排序order by 和分组查询group
by。
(3)Using index
Using index 代表表示相应的select 操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错!
如果同时出现using where,表明索引被用来执行索引键值的查找;如果没有同时出现using where,表明索引只是
用来读取数据而非利用索引执行查找。
利用索引进行了排序或分组。
(4)Using where
表明使用了where 过滤。
(5)Using join buffer使用了连接缓存。
(6)impossible where
where 子句的值总是false,不能用来获取任何元组。

单表使用索引常见的索引失效

查询的字段按照顺序在索引中都可以匹配到!
SQL 中查询字段的顺序,跟使用索引中字段的顺序,没有关系。优化器会在不影响SQL 执行结果的前提下,给你自动地优化。

查询字段与索引字段顺序的不同会导致,索引无法充分使用,甚至索引失效!
原因:使用复合索引,需要遵循最佳左前缀法则,即如果索引了多列,要遵守最左前缀法则。指的是查询从索
引的最左前列开始并且不跳过索引中的列。

*1.不在索引列上做任何操作(计算、函数、(自动or 手动)类型转换),会导致索引失效而转向全表扫描。结论:等号左边无计算!
2.在查询列上做了转换 如a=1000 ->a=‘1000’ 结论:等号右边无转换!
3.索引列上不能有范围查询 建议:将可能做范围查询的字段的索引顺序放在最后
4.即查询列和索引列一直,不要写select !
5.mysql 在使用不等于(!= 或者<>)时,有时会无法使用索引会导致全表扫描。
6.is not null 用不到索引,is null 可以用到索引。
7.like 的前后模糊匹配 前缀不能出现模糊匹配!如’%a’,’%a%’ 会使索引失效,'a%'可以用
8.减少使用or,使用union all 或者union 来替代

全职匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
LIKE 百分写最右,覆盖索引不写*;
不等空值还有OR,索引影响要注意;
VAR 引号不可丢,SQL 优化有诀窍。

left join
结论:
①在优化关联查询时,只有在被驱动表上建立索引才有效!
②left join 时,左侧的为驱动表,右侧为被驱动表!
④结论:inner join 时,mysql 会自己帮你把小结果集的表选为驱动表。
⑤straight_join: 效果和inner join 一样,但是会强制将左侧作为驱动表!
结论:
子查询尽量不要放在被驱动表,有可能使用不到索引;
left join时,尽量让实体表作为被驱动表。
结论:能够直接多表关联的尽量直接关联,不用子查询!
结论: 在范围判断时,尽量不要使用not in 和not exists,使用left join on xxx is null 代替。
结论: 无过滤,不索引。where,limt 都相当于一种过滤条件,所以才能使用上索引!(用order by 必须用上where过滤才使用索引,group by 则不需要)

默认情况下,MySQL 数据库没有开启慢查询日志,需要我们手动来设置这个参数。
当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。
慢查询日志支持将日志记录写入文件。
SHOW VARIABLES LIKE ‘%slow_query_log%’;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 性能优化 1.1 避免频繁 commit,尤其是把 commit 写在循环体中每次循环都进行commit。 1.2 使用绑定变量,避免常量的直接引用。 示例:以下书写不符合本规范。 INSERT INTO sm_users (user_id, user_name, created_by, creation_date) VALUES (1, 'Tang', -1, SYSDATE); 建议用如下方式操作: DECLARE v_user_id sm_users.user_id%TYPE; v_user_name sm_users_user_name%TYPE; v_created_by sm_users.created_by%TYPE; v_creation_date sm_users.creation_date%TYPE; BEGIN ... INSERT INTO sm_users (user_id, user_name, created_by, creation_date) VALUES (v_user_id, v_user_name, v_created_by, v_creation_date); END; 1.3 Operator 的使用规范  IN  比较容易写及清晰易懂  但效能是比较低的  ORACLE试图将其转换成多个表的连接,如果转换不成功则先执行IN里面的子查询,再查询外层的表记录,如果转换成功则直接采用多个表的连接方式查询。由此可见用IN的SQL至少多了一个转换的过程。一般的SQL都可以转换成功,但对于含有分组统计等方面的SQL就不能转换了。  NOT IN  此操作是强列推荐不使用的,因为不能应用表的索引。  推荐方案:用NOT EXISTS 或(Outer-Join+判断为空)方案代替 例如: SELECT deptno FROM dept WHERE deptno NOT IN(SELECT deptno FROM emp) 建议写成: SELECT deptno FROM dept, emp WHERE dept.deptno = emp.deptno(+) AND emp.deptno IS NULL  <>  永远不会用到索引的  推荐方案:用其它相同功能的操作运算代替,如: a<>0 改为 a>0 or a<0 a<>’’ 改为 a>’’  IS NULL 或IS NOT NULL  一般是不会应用索引的,因为B-tree索引是不索引空值的。  推荐方案:用其它相同功能的操作运算代替,如: a is not null 改为 a>0 或a>’’  不允许字段为空,而用一个default代替空值,如业扩申请中状态区位不允许为空, default为申请。  > 及 <  有索引就会采用索引查找  但有的情况下可以对它进行优化  如一个表有100万记录,一个数值型字段A,30万记录的A=0,30万记录的A=1,39万记录的A=2,1万记录的A=3。那么执行A>2与A>=3的效果就有很大的区别了,因为A>2时ORACLE会先找出为2的记录索引再进行比较,而A>=3时ORACLE则直接找到=3的记录索引。  LIKE  LIKE可以应用通配符查询,里面的通配符组合可能达到几乎是任意的查询,但是如果用得不好则会产生性能上的问题,如LIKE ‘%5400%’ 这种查询不会引用索引,而LIKE ‘X5400%’则会引用范围索引。性能肯定大大提高。  UNION  SQL在运行时先取出数个查询的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。  实际大部分应用中是不会产生重复的记录,推荐采用UNION ALL操作符替代UNION,因为UNION ALL操作只是简单的将两个结果合并后就返回。  Exists 示例:当有 A、B 两个结果集,当结果集 B 很大时,A 较小时,适用 exists,如: SELECT * FROM a WHERE EXISTS(SELECT 1 FROM b WHERE a.COLUMN = b.COLUMN); 当结果集 A 很大时,B 很小时,适用 in,如: SELECT * FROM a WHERE a.COLUMN IN(SELECT b.COLUMN FROM b) 1.4 SQL书写的影响  同一功能同一性能不同写法SQL的影响  Select * from zl_yhjbqk  Select * from dlyx.zl_yhjbqk(带表所有者的前缀)  Select * from DLYX.ZL_YHJBQK(大写表名)  Select * from DLYX.ZL_YHJBQK(中间多了空格)  以上四个SQL在ORACLE分析整理之后产生的结果及执行的时间是一样的,但是从ORACLE共享内存SGA的原理,可以得出ORACLE对每个SQL 都会对其进行一次分析,并且占用共享内存,如果将SQL的字符串及格式写得完全相同则ORACLE只会分析一次,共享内存也只会留下一次的分析结果,这不仅可以减少分析SQL的时间,而且可以减少共享内存重复的信息,ORACLE也可以准确统计SQL的执行频率。  WHERE后面的条件顺序影响  Select * from zl_yhjbqk where dy_dj = '1KV以下' and xh_bz=1  Select * from zl_yhjbqk where xh_bz=1 and dy_dj = '1KV以下'  以上两个SQL中dy_dj(电压等级)及xh_bz(销户标志)两个字段都没进行索引,所以执行的时候都是全表扫描,第一条SQL的dy_dj = '1KV以下'条件在记录集内比率为99%,而xh_bz=1的比率只为0.5%,在进行第一条SQL的时候99%条记录都进行dy_dj及xh_bz的比较,而在进行第二条SQL的时候0.5%条记录都进行dy_dj及xh_bz的比较,以此可以得出第二条SQL的CPU占用率明显比第一条低。  查询表顺序的影响  在FROM后面的表中的列表顺序会对SQL执行性能影响,在没有索引及ORACLE没有对表进行统计分析的情况下ORACLE会按表出现的顺序进行链接,由此因为表的顺序不对会产生十分耗服务器资源的数据交叉。(注:如果对表进行了统计分析,ORACLE会自动先进小表的链接,再进行大表的链接)  对条件字段的一些优化  采用函数处理的字段不能利用索引,如: substr(hbs_bh,1,4)=’5400’,优化处理:hbs_bh like ‘5400%’ trunc(sk_rq)=trunc(sysdate), 优化处理: sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)  进行了显式或隐式的运算的字段不能进行索引,如: ss_df+20>50,优化处理:ss_df>30 ‘X’||hbs_bh>’X5400021452’,优化处理:hbs_bh>’5400021542’ sk_rq+5=sysdate,优化处理:sk_rq=sysdate-5 hbs_bh=5401002554,优化处理:hbs_bh=’ 5401002554’ 注:此条件对hbs_bh 进行隐式的to_number转换,因为hbs_bh字段是字符型  条件内包括了多个本表的字段运算时不能进行索引,如: ys_df>cx_df,无法进行优化 qc_bh||kh_bh=’5400250000’,优化处理:qc_bh=’5400’ and kh_bh=’250000’  HINT  是在ORACLE产生的SQL分析执行路径不满意的情况下要用到的。它可以对SQL进行以下方面的提示  目标方面的提示:  COST(按成本优化)  RULE(按规则优化)  CHOOSE(缺省)(ORACLE自动选择成本或规则进行优化)  ALL_ROWS(所有的行尽快返回)  FIRST_ROWS(第一行资料尽快返回)  执行方法的提示:  USE_NL(使用NESTED LOOPS方式联合)  USE_MERGE(使用MERGE JOIN方式联合)  USE_HASH(使用HASH JOIN方式联合)  索引提示:  INDEX(TABLE INDEX)(使用提示的表索引进行查询)  其它高级提示(如并行处理等等) 1.5 索引的规则: 建立索引常用的原则如下: 1. 表的主键、外键必须有索引 2. 数据量超过 1000 行的表应该有索引 3. 经常与其它表进行连接的表,在边接字段上应建立索引 4. 经常出现在 where 子句中的字段且过滤性极强的,特别是大表的字段,应该建立索引 5. 索引字段,尽量避免值为 null 6. 复合索引的建立需要仔细分析;尽量考虑用单字段索引代替:  正确选择复合索引中的第一个字段,一般是选择性较好的且在 where 子句中常的字段上。  复合索引的几个字段是否经常同时以and方式出现在where子句中?单字段查询是否极少甚至没有?如果是,则可以建立复合索引;否则考虑单字段索引。  如果复合索引中包含的字段经常单独出现在 where 子句中,则分解为多个单字段索引。  如果复合索引所包含的字段超过 3 个,那么仔细考虑其必要性,考虑减少复合的字段。  如果既有单字段索引,又有这几个字段上的复合索引,一般可以删除复合索引; 7. 频繁 DDL 的表,不要建立太多的索引 8. 删除无用的索引,避免对执行计划造成负面影响 9. 让 SQL 语句用上合理的索引,合理让 SQL 语句使用索引的原则如下:  首先,看是否用上了索引,对于该使用索引而没有用上索引的 SQL 语句,应该想办法用上索引。  其次,看是否用上正确的索引了,特别复杂的 SQL 语句,当其中 where 子句包含多个带有索引的字段时,更应该注意索引的选择是否合理。错误的索引不仅不会带来性能的提高,相反往往导致性能的降低。  针对如何用上合理的索引,以 Oracle 数据中的例子进行说明:  任何对列的操作都可能导致全表扫描,这里所谓的操作包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等式的右边,甚至去掉函数。  避免不必要的类型转换,要了解“隐藏”的类型转换。  增加查询的范围,限制全范围的搜索。  索引选择性低,但资料分布差异很大时,仍然可以利用索引提高效率。  Oracle 优化器无法用上合理索引的情况下,利用 hint 强制指定索引。  使用复合索引且第一个索引字段没有出现在 where 中时,建议使用 hint 强制。 1.6 索引使用优化  建立Plan_Table CREATE TABLE PLAN_TABLE ( STATEMENT_ID VARCHAR2(30), TIMESTAMP DATE, REMARKS VARCHAR2(80), OPERATION VARCHAR2(30), OPTIONS VARCHAR2(30), OBJECT_NODE VARCHAR2(128), OBJECT_OWNER VARCHAR2(30), OBJECT_NAME VARCHAR2(30), OBJECT_INSTANCE NUMBER(38), OBJECT_TYPE VARCHAR2(30), OPTIMIZER VARCHAR2(255), SEARCH_COLUMNS NUMBER(38), ID NUMBER(38), PARENT_ID NUMBER(38), POSITION NUMBER(38), OTHER LONG )  Syntax 说明: explain plan set statement_id = user_define for select ... 将结果显示 SELECT LPAD(' ', 2 *(LEVEL - 1)) || operation op, options, object_name, POSITION FROM plan_table START WITH ID = 0 AND STATEMENT_ID = user_define CONNECT BY PRIOR ID = parent_id AND STATEMENT_ID = user_define  示例 如要测试下面SQL: SELECT c.short, a.cday, a.card_no, a.qty FROM sales.stockiohis a, sales.product_info b, sales.vendor c WHERE a.card_no = b.card_no AND b.vendorid = c.vendorid AND a.produce_no = '2007090001' AND a.CATEGORY = '10' AND a.iotype = '1' 新增文件:例 d:\mydoc\plan.sql '0001'为user_define为使用者自定义编号 EXPLAIN PLAN SET STATEMENT_ID = '0001' FOR SELECT 'X' FROM sales.stockiohis a ,sales.product_info b ,sales.vendor c WHERE a.card_no = b.card_no AND b.vendorid = c.vendorid AND a.produce_no = '2007090001' AND a.CATEGORY = '10' AND a.iotype = '1' / SET arraysize 1 SET line 100 COLUMN op format a40 COLUMN object_name format a20 COLUMN options format a20 SELECT LPAD(' ', 2 *(LEVEL - 1)) || operation op, options, object_name, POSITION FROM plan_table START WITH ID = 0 AND STATEMENT_ID = '0001' CONNECT BY PRIOR ID = parent_id AND STATEMENT_ID = '0001' / DELETE FROM plan_table WHERE STATEMENT_ID = '0001' / COMMIT / 结果 1.7 避免不必要的排序 说明:对查询结果进行排序会大大的降低系统的性能,group与union都会对数据作排序,要耗费较多的内存,视状况用union all既可,不然有时数据太大又要进行union的排序,会导致Oracle数据库SORT_AREA_SIZE不足发生系统错误。 1.8 对于数字型的Primary Key,建议用序列 sequence 产生。 说明:除非是单据的单号,要求必须是唯一,并且依据流水号不可以跳号,不然在大量交易的表格中,不在乎跳耗时,要取得唯一的Primary Key 建议使用Oracle Sequence这样速度会较快,而且不会有锁定(Lock)的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值