精华内容
下载资源
问答
  • Jvm调优: 1.调内存 (1)调堆内存大小 -Xms设置堆的最小空间大小。 -Xmx设置堆的最大空间大小。 -XX:NewSize设置新生代最小空间大小。 -XX:MaxNewSize设置新生代最大空间大小。 -Xss:设置每个线程的堆栈大小...

    Jvm调优:

    1.调内存

    (1)调堆内存大小

    -Xms设置堆的最小空间大小。

    -Xmx设置堆的最大空间大小。

    -XX:NewSize设置新生代最小空间大小。

    -XX:MaxNewSize设置新生代最大空间大小。

    -Xss:设置每个线程的堆栈大小。

    (2)调方法区内存大小

    -XX:MetaspaceSize 设置元数据区最小空间。 (JDK8)

    -XX:MaxMetaspaceSize 设置元数据区最大空间。(JDK8)

    jsp:查看进程端口号

    jconsole分析:内存的大小

    内存分析工具:

    Memory Analyzer Tool(MAT)是一个强大的基于的内存分析工具,可以帮助我们找到内存泄露,减少内存消耗。

    jmap -dump:format=b,file=D:\temp\07.hprof 进程号

    2.调GC算法

    串行算法、并行回收算法(cms)

    tomcat优化:

    1.内存优化

    Windows平台下在bin目录下的catalina.bat文件中,找到@echo off然后再它的下面一行添加如下类似语句。

    SET CATALINA_OPTS= -Xms512m -Xmx512m -Xmn125m

    参数说明:

    -server:一定要作为第一个参数,在多个CPU时性能佳

    -Xms:java Heap初始大小。 默认是物理内存的1/64。

    -Xmx:java heap最大值。建议均设为物理内存的一半。不可超过物理内存。

    -Xmn:young generation(年轻代)的heap大小。一般为Xmx的3、4分之一

    -XX:MetaspaceSize=128m 初始元空间大小,默认一般为21m。

    -XX:MaxMetaspaceSize=256m 最大元空间大小,默认无上限,由OS内存决定

    2.网络优化

    默认使用http1.1

    <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000"

    redirectPort="8443" />

    优化使用nio2

    <Connector port="8080" protocol="org.apache.coyote.http11.

    Http11Nio2Protocol"connectionTimeout="20000" redirectPort="8443" />

    3.线程池优化

    <Connector port="8080" protocol="org.apache.coyote.http11.

    Http11Nio2Protocol" connectionTimeout="20000"redirectPort="8443" maxThreads="10" />

    数据库优化:

    软优化:

    1.查询语句优化:首先我们可以用EXPLAIN或DESCRIBE(简写:DESC)命令分析一条查询语句的执行信息.

    2.优化子查询:在MySQL中,尽量使用JOIN来代替子查询.因为子查询需要嵌套查询,嵌套查询时会建立一张临时表,临时表的建立和删除都会有较大的系统开销,而连接查询不会创建临时表,因此效率比嵌套子查询高.

    3.使用索引

    4.分解表:

    5.使用中间表:对于将大量连接查询的表可以创建中间表,从而减少在查询时造成的连接耗时.

    6.增加冗余字段:类似于创建中间表,增加冗余也是为了减少连接查询.

    硬优化:

    (1)优化三大硬件

             1.配置多核和频率高的cpu,多核可以执行多个线程.

              2.配置大内存,提高内存,即可提高缓存区容量,因此能减少磁盘I/O时间,从而提高响应速度.

              3.配置高速磁盘或合理分布磁盘:高速磁盘提高I/O,分布磁盘能提高并行操作的能力.

    (2)优化数据库参数

           1.key_buffer_size:索引缓冲区大小

           2.table_cache:能同时打开表的个数

           3.设置query_cache_size和query_cache_type:前者是查询缓冲区大小,后者是前面参数的开关,0表示不使用缓冲区,1表示使用缓冲区,但可以在查询中使用SQL_NO_CACHE表示不要使用缓冲区,2表示在查询中明确指出使用缓冲区才用缓冲区,即SQL_CACHE.

            4.设置sort_buffer_size:排序缓冲区

    (3)分库分表

    (4)缓存集群

    设计模式:

    创建型模式:

    • 简单工厂模式:创建对象时降低耦合(DefaultAopProxyFactory)
    • 单例设计模式:饿汉式单例设计模式 懒汉式单例设计模式
    • 建造者设计模式:解决问题:将创建对象的代码分离出来

    解决方案:*builder(SqlSessionFactoryBuilder)

    结构型模式:

    • 适配器模式 (Adapter):解决问题:一个类或接口不适合别人使用

           解决方案:增加一个适配器类(HandlerInterceptor)

    • 责任链设计模式:解决问题:使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

          解决方案:接口,实现类,chain(InterceptorChain)

    • 观察者设计模式:解决问题:上一层(ui层)下一层(db层),db中的数据发生变化,ui应该知道,更新界面,目标(db)发生变化,观察者(ui)应该知道。

           解决方法:Interface Observer Class 观察者implement Observer

           目标{List<Observer> 发生变化For (list){通知观察者}}

    • 装饰设计模式:解决问题:类功能不够, 解决方法:增加新类

             案例: inputStream ,ObjectInputStream(inputStream)

    • 代理设计模式:解决问题:目标代码写好,增加扩展功能

             解决方法:增加代理,代理中实现扩展功能,代理再去调用目标代码

    Bootstrap是基于HTML、CSS、JavaScript 开发的简洁、直观、强悍的前端开发框架,使得 Web 开发更加快捷。 提供了优雅的HTML和CSS规范,能制作响应式网页。

    Idea(编辑工具) svn(项目整合) vue(前端框架)

     

     

    展开全文
  • 数据库调优分享-mysql

    2016-05-13 09:56:37
    数据库调优分享------参考一本mysql资料书日常的困扰**反映查询某个数据越来越慢,怎么办?数据库监控页面显示某个操作频繁执行,每次执行都非常耗时,怎么办?1.Sql优化2.合理使用索引一、sql优化—常用方法1)not ...
    数据库调优分享------参考一本mysql资料书 

    日常的困扰 
    **反映查询某个数据越来越慢,怎么办? 
    数据库监控页面显示某个操作频繁执行,每次执行都非常耗时,怎么办? 

    1.Sql优化 
    2.合理使用索引 

    一、sql优化—常用方法 
    1)not in 子查询优化 
    2)模糊匹配 like ‘%abc%’ 
    3)limit分页优化 
    4)count(*)统计数据如何加快速度 
    5)or条件如何优化 
    6)用where子句代替having子句 


    1、not in 子查询优化 
      SELECT count(*) FROM t_cps t1  where t1.flag>=2 and  sample_md5 not in (select sample_hash from t_sfa_sample  t2 where t2.sample_hash=t1.sample_md5); 
    -1052661行记录 
    33.530s 


    SELECT count(*) FROM t_cps t1  where t1.flag>=2 and not exists(select sample_hash from t_sfa_sample   t2 where t2.sample_hash=t1.sample_md5);  
    -1052661行记录 
    18.617s 

    SELECT count(*) FROM t_cps t1 left join t_sfa_sample t2 on t1.sample_md5=t2.sample_hash where t1.flag>=2  and t2.sample_hash is null; 
    -1052661行记录 
    14.544s 

    生产环境中,尽量避免使用子查询,可用表连接join代替。可避免mysql在内存中创建临时表 

    in和exists 
    SELECT count(*) FROM t_cps t1  where t1.flag>=2 and  sample_md5  in (select sample_hash  from t_sfa_sample   t2 where t2.sample_hash=t1.sample_md5); 
    1227992行记录 
    30.762s 

    SELECT count(*) FROM t_cps t1  where t1.flag>=2 and  exists (select sample_hash from t_sfa_sample   t2 where t2.sample_hash=t1.sample_md5); 
    1227992行记录 
    15.581s 

    in和exists执行时: 
    in是先执行子查询中的查询,然后再执行主查询。 
    exists是先执行主查询,即外层表的查询,然后再执行子查询 
    exists 和 in 在执行时效率单从执行时间来说差不多,exists要稍微优于in。在使用时一般应该是用exists而不用in 

    而在not in 和 not exists比较时,not exists的效率要比not in的效率要高。 
    但也有少数时候并非如此。 
    建议是尽量多使用exists和not exists,少用in 和not in 


    2、模糊匹配 like ‘%abc%’ 
    mysql> explain select * from update_log_test where msg like 'e%'; 
    +----+-------------+-----------------+-------+---------------+---------+---------+------+------+-----------------------+ 
    | id | select_type | table           | type  | possible_keys | key     | key_len | ref  | rows | Extra                 | 
    +----+-------------+-----------------+-------+---------------+---------+---------+------+------+-----------------------+ 
    |  1 | SIMPLE      | update_log_test | range | idx_msg       | idx_msg | 768     | NULL |    1 | Using index condition | 
    +----+-------------+-----------------+-------+---------------+---------+---------+------+------+-----------------------+ 
    1 row in set (0.00 sec) 

    mysql> explain select * from update_log_test where msg like '%e%'; 
    +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ 
    | id | select_type | table           | type | possible_keys | key  | key_len | ref  | rows | Extra       | 
    +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ 
    |  1 | SIMPLE      | update_log_test | ALL  | NULL          | NULL | NULL    | NULL |    4 | Using where | 
    +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ 
    1 row in set (0.00 sec) 

    like ‘abc%’可以用到索引,但like‘%abc%’却不行。 

    SELECT * FROM books  WHERE name like "MySQL%" ; 
    但是如果换用下面的查询,返回的结果一样,但速度就要快上很多: 
    SELECT * FROM books  WHERE name>="MySQL"and name<"MySQM" ; 

    补充:explain列的解释 

    table  显示这一行的数据是关于哪张表的 
    type   这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、index和ALL 
    possible_keys  显示可能应用在这张表中的索引。如果为空,没有可能的索引。 
    key 实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引 

    key_len  使用的索引的长度。在不损失精确性的情况下,长度越短越好 
    ref     显示索引的哪一列被使用了,显示了哪些字段或者常量被用来和 key配合从表中查询记录出来。 
    rows   MYSQL认为必须检查的用来返回请求数据的行数 
    Extra  关于MYSQL如何解析查询的额外信息。这里可以看到的坏的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,检索会很慢 

    type不同连接类型的解释(按照效率高低的顺序排序) 

    const   索引可以是主键或惟一索引,因为只有一行,这个值实际就是常数,因为MYSQL先读这个值然后把它当做常数来对待 
    mysql> explain select * from update_log_20141111 where id=2; 
    +----+-------------+---------------------+-------+---------------+---------+---------+-------+------+-------+ 
    | id | select_type | table               | type  | possible_keys | key     | key_len | ref   | rows | Extra | 
    +----+-------------+---------------------+-------+---------------+---------+---------+-------+------+-------+ 
    |  1 | SIMPLE      | update_log_20141111 | const | PRIMARY       | PRIMARY | 4       | const |    1 | NULL  | 
    +----+-------------+---------------------+-------+---------------+---------+---------+-------+------+-------+ 

    eq_ref     从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为主键或惟一键的全部时使用 
    mysql> explain select * from t1,t2 where t1.id=t2.id; 
    +----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+ 
    | id | select_type | table | type   | possible_keys | key     | key_len | ref        | rows | Extra | 
    +----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+ 
    |  1 | SIMPLE      | t2    | ALL    | PRIMARY       | NULL    | NULL    | NULL       |    9 | NULL  | 
    |  1 | SIMPLE      | t1    | eq_ref | PRIMARY       | PRIMARY | 4       | test.t2.id |    1 | NULL  | 
    +----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+ 
    2 rows in set (0.00 sec) 

    ref      只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于根据索引匹配的记录多少—越少越好 
    mysql> explain select * from update_log_20141110 t1,update_log_test t2 where t1.action=t2.action; 
    +----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+ 
    | id | select_type | table | type | possible_keys | key      | key_len | ref            | rows | Extra       | 
    +----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+ 
    |  1 | SIMPLE      | t1    | ALL  | i_action      | NULL     | NULL    | NULL           |    2 | Using where | 
    |  1 | SIMPLE      | t2    | ref  | i_action      | i_action | 2       | test.t1.action |    1 | NULL        | 
    +----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+ 
    2 rows in set (0.00 sec) 

    range   返回一个范围中的行,比如使用>或<查找东西时 
    mysql> explain select * from t1 where id>=9900 order by id limit 10; 
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
    | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       | 
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
    |  1 | SIMPLE      | t1    | range | PRIMARY       | PRIMARY | 4       | NULL |  101 | Using where | 
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
    1 row in set (0.00 sec) 

    index   对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据) 
    ALL      对每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免 

    Extra 列返回的描述的意义 

    Distinct  一旦MYSQL找到了与行相联合匹配的行,就不再搜索了 
    Not exists  MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索 
    Record(index map:#)没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一 
    Using filesort   看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行 
    Using index  列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候 
    Using temporary 看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上 
    Using where 使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题 


    3、limit分页优化 
    Select  * from t1 order by id limit 9900,10; 

    上面的语句,虽然用到了id索引,但是从第一行开始起定位至9900行,然后再扫描后10行,相当于进行了一次全扫描,显然效率不高。 

    Select * from t1 where id>=9900 order by id limit 10; 
    利用id索引直接定位到9900行,然后在扫描出后10行,相当于一个range范围扫描 

    mysql> explain select  * from t1 order by id limit 9900,10; 
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
    | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra | 
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
    |  1 | SIMPLE      | t1    | index | NULL          | PRIMARY | 4       | NULL | 9910 | NULL  | 
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
    1 row in set (0.00 sec) 

    mysql> explain select * from t1 where id>=9900 order by id limit 10; 
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
    | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       | 
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
    |  1 | SIMPLE      | t1    | range | PRIMARY       | PRIMARY | 4       | NULL |  101 | Using where | 
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
    1 row in set (0.00 sec) 

    4、count(*)统计数据如何加快速度 
    select count(*)  from update_log; 
    select count(*)  from update_log  where sid>=0; 利用辅助索引 

    select count(distinct k) from t; 
    select count(*) from (select distinct k from t) tmp;  利用索引来做排重操作。 

    注意:innodb count(*)必须全表扫,而不像myisam那样有一个计数器,直接从中取出数据。Innodb必须要全表扫一次才能得到count,而且会锁表。 


    5、or条件如何优化 

    select * from user where name='d' or age=31; 
    name和age都建立了索引,但explain发现这个or条件用不到索引。 

    改成union all结果集合并 
    select * from user where name='d' union all select * from user where age=31; 

    6、用where子句代替having子句 
    select * from user group by id having id>40 limit 3; 
    select * from user where id>40 group by id limit 3; 

    having只会在检索出所有记录之后才对结果集进行过滤。这个处理需要排序、总计等操作。 

    如果能通过where子句限制记录的数目,那就能减少这方面的开销。 

    SQL优化的一般步骤 
    1、通过 show status 命令了解各种SQL的执行频率 
        show status like 'uptime' 当前MySQL运行时间 
        show status like 'com_select' 当前MySQL执行了多少次查询 
        show status like 'com_insert' 当前MySQL执行了多少次添加 
        show status like 'com_update' 当前MySQL执行了多少次更新 
        show status like 'com_delete' 当前MySQL执行了多少次删除 
        show status 语法: 
        show [session|global] status like ''; 
        如果不写 [session|global] 表示默认是 session 指取出当前窗口的执行情况 
        如果想看所有(mysql启动到现在)的情况 加上 global 
        show global status like 'com_insert'; 

    2、 定位执行效率较低的SQL语句 (重点select) 
    3、通过 explain 分析低效率的SQL语句的执行情况 
    4、确定问题并采取相应的优化措施 


    二、合理使用索引 
    使用索引,why? 
    单列索引和联合索引 
    字段使用函数,将不能走索引 
    当取出的数据量超过表中数据的20%,索引是否有效? 
    order by 和group by优化 
    全文索引 

    1、适当的索引对应用的性能来说至关重要。 

    2、索引只对select有加速作用,但对写入(insert,update、delete)操作会带来额外的开销,如果带有一个或多个索引,那么数据更新的时候,mysql也要更新各个索引。 

    3、并不是所有经常查询的列都适合创建索引,区分度不高的,通常走全表扫浏览会更快。例如性别,只有男女两种,就不适合。 

    4、一条sql只能用一个索引,如果有多个,优化器会选择最优的。 

    1、单列索引和联合索引 

    mysql> create index i_s_time on update_log(server,time); 

    联合索引要遵循最左侧原则 
    mysql> explain select * from update_log where server='115.29.138.24' and time='13:00:00'; 
    +----+-------------+------------+------+-----------------+----------+---------+-------------+------+-----------------------+ 
    | id | select_type | table      | type | possible_keys   | key      | key_len | ref         | rows | Extra                 | 
    +----+-------------+------------+------+-----------------+----------+---------+-------------+------+-----------------------+ 
    |  1 | SIMPLE      | update_log | ref  | i_time,i_s_time | i_s_time | 50      | const,const |    7 | Using index condition | 
    +----+-------------+------------+------+-----------------+----------+---------+-------------+------+-----------------------+ 
    1 row in set (0.00 sec) 

    mysql> explain select * from update_log where server='115.29.138.24'; 
    +----+-------------+------------+------+---------------+----------+---------+-------+---------+-----------------------+ 
    | id | select_type | table      | type | possible_keys | key      | key_len | ref   | rows    | Extra                 | 
    +----+-------------+------------+------+---------------+----------+---------+-------+---------+-----------------------+ 
    |  1 | SIMPLE      | update_log | ref  | i_s_time      | i_s_time | 46      | const | 2653264 | Using index condition | 
    +----+-------------+------------+------+---------------+----------+---------+-------+---------+-----------------------+ 
    1 row in set (0.00 sec) 


    mysql> explain select * from update_log where server='115.29.138.24' and client='14.197.74.21' and time='13:00:00'; 
    +----+-------------+------------+------+-----------------+----------+---------+-------------+------+------------------------------------+ 
    | id | select_type | table      | type | possible_keys   | key      | key_len | ref         | rows | Extra                              | 
    +----+-------------+------------+------+-----------------+----------+---------+-------------+------+------------------------------------+ 
    |  1 | SIMPLE      | update_log | ref  | i_time,i_s_time | i_s_time | 50      | const,const |    7 | Using index condition; Using where | 
    +----+-------------+------------+------+-----------------+----------+---------+-------------+------+------------------------------------+ 
    1 row in set (0.00 sec) 


    mysql> explain select * from update_log where  time='13:00:00'; 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-------------+ 
    | id | select_type | table      | type | possible_keys | key  | key_len | ref  | rows     | Extra       | 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-------------+ 
    |  1 | SIMPLE      | update_log | ALL  | NULL          | NULL | NULL    | NULL | 21615394 | Using where | 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-------------+ 
    1 row in set (0.00 sec) 

    2、字段使用函数,将不能走索引 --mysql目前还不支持函数索引 

    mysql> explain select * from update_log where year(date)<2014; 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-------------+ 
    | id | select_type | table      | type | possible_keys | key  | key_len | ref  | rows     | Extra       | 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-------------+ 
    |  1 | SIMPLE      | update_log | ALL  | NULL          | NULL | NULL    | NULL | 21615394 | Using where | 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-------------+ 
    1 row in set (0.00 sec) 
    在where后面的查询条件字段使用了date()函数,是不会用到索引的。 

    mysql> explain select * from update_log where date<'2014-01-01'; 
    +----+-------------+------------+-------+---------------+------+---------+------+------+-----------------------+ 
    | id | select_type | table      | type  | possible_keys | key  | key_len | ref  | rows | Extra                 | 
    +----+-------------+------------+-------+---------------+------+---------+------+------+-----------------------+ 
    |  1 | SIMPLE      | update_log | range | date          | date | 4       | NULL |    1 | Using index condition | 
    +----+-------------+------------+-------+---------------+------+---------+------+------+-----------------------+ 
    1 row in set (0.00 sec) 

    同样的情形也会发生在对数值型字段进行计算的时候: 
    SELECT * FROM t1  WHERE Amount/7<24; 
    SELECT * FROM t1  WHERE Amount<24*7; 

    3、无引号导致全表扫描,无法使用索引 

    mysql> explain select * from update_log_test where msg=123; 
    +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ 
    | id | select_type | table           | type | possible_keys | key  | key_len | ref  | rows | Extra       | 
    +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ 
    |  1 | SIMPLE      | update_log_test | ALL  | i_msg         | NULL | NULL    | NULL |    4 | Using where | 
    +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ 
    1 row in set (0.00 sec) 

    mysql> explain select * from update_log_test where msg='yoyo'; 
    +----+-------------+-----------------+------+---------------+-------+---------+-------+------+-----------------------+ 
    | id | select_type | table           | type | possible_keys | key   | key_len | ref   | rows | Extra                 | 
    +----+-------------+-----------------+------+---------------+-------+---------+-------+------+-----------------------+ 
    |  1 | SIMPLE      | update_log_test | ref  | i_msg         | i_msg | 768     | const |    1 | Using index condition | 
    +----+-------------+-----------------+------+---------------+-------+---------+-------+------+-----------------------+ 
    由于msg是varchar类型,因此查询的时候,必须加‘’ 
    数字当字符类型使用时,也一定要加上。 


    4、当取出的数据量超过表中数据的20%,优化器认为全表扫更快,不会走索引 

    mysql> explain select * from update_log where time<'14:00:00'; 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-------------+ 
    | id | select_type | table      | type | possible_keys | key  | key_len | ref  | rows     | Extra       | 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-------------+ 
    |  1 | SIMPLE      | update_log | ALL  | i_time        | NULL | NULL    | NULL | 21615394 | Using where | 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-------------+ 
    1 row in set (0.00 sec) 

    mysql> explain select * from update_log where time<'14:00:00' and time>'13:00:00'; 
    +----+-------------+------------+-------+---------------+--------+---------+------+---------+-----------------------+ 
    | id | select_type | table      | type  | possible_keys | key    | key_len | ref  | rows    | Extra                 | 
    +----+-------------+------------+-------+---------------+--------+---------+------+---------+-----------------------+ 
    |  1 | SIMPLE      | update_log | range | i_time        | i_time | 4       | NULL | 3013332 | Using index condition | 
    +----+-------------+------------+-------+---------------+--------+---------+------+---------+-----------------------+ 
    1 row in set (0.00 sec) 

    5、order by 和group by优化 

    mysql> explain select * from update_log where server='115.29.138.24' order by time; 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-----------------------------+ 
    | id | select_type | table      | type | possible_keys | key  | key_len | ref  | rows     | Extra                       | 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-----------------------------+ 
    |  1 | SIMPLE      | update_log | ALL  | NULL          | NULL | NULL    | NULL | 21615394 | Using where; Using filesort | 
    +----+-------------+------------+------+---------------+------+---------+------+----------+-----------------------------+ 
    1 row in set (0.00 sec) 

    创建联合索引 
    mysql> create index i_s_time on update_log(server,time); 
    Query OK, 0 rows affected (3 min 18.94 sec) 
    Records: 0  Duplicates: 0  Warnings: 0 

    mysql> explain select * from update_log where server='115.29.138.24' order by time; 
    +----+-------------+------------+------+---------------+----------+---------+-------+---------+------------------------------------+ 
    | id | select_type | table      | type | possible_keys | key      | key_len | ref   | rows    | Extra                              | 
    +----+-------------+------------+------+---------------+----------+---------+-------+---------+------------------------------------+ 
    |  1 | SIMPLE      | update_log | ref  | i_s_time      | i_s_time | 46      | const | 2653264 | Using index condition; Using where | 
    +----+-------------+------------+------+---------------+----------+---------+-------+---------+------------------------------------+ 
    1 row in set (0.01 sec) 


    如果order by 后面有多个字段排序,它们的顺序要一致,如果一个是降序,一个是升序,也会出现using filesort排序。 

    6、全文索引 
    全文索引:主要是针对文件,文本的索引,比如文章(5.6开始innodb也支持) 
    字段类型:char、varchar、text 
    全文搜索通过 MATCH() 函数完成. 

    mysql> create table articles( 
        -> id int unsigned auto_increment not null primary key, 
        -> title varchar(200), 
        -> body text, 
        -> fulltext(title,body)); 
    Query OK, 0 rows affected (0.05 sec) 

    mysql> INSERT INTO articles VALUES 
        -> (NULL,'MySQL Tutorial', 'DBMS stands for DataBase ...'), 
        ->  (NULL,'How To Use MySQL Efficiently', 'After you went through a ...'), 
        -> (NULL,'Optimising MySQL','In this tutorial we will show ...'), 
        -> (NULL,'1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), 
        -> (NULL,'MySQL vs. YourSQL', 'In the following database comparison ...'), 
        -> (NULL,'MySQL Security', 'When configured properly, MySQL ...'); 
    Query OK, 6 rows affected (0.01 sec) 
    Records: 6  Duplicates: 0  Warnings: 0 

    mysql> explain select * from articles where match(title,body) against('database'); 
    +----+-------------+----------+----------+---------------+-------+---------+------+------+-------------+ 
    | id | select_type | table    | type     | possible_keys | key   | key_len | ref  | rows | Extra       | 
    +----+-------------+----------+----------+---------------+-------+---------+------+------+-------------+ 
    |  1 | SIMPLE      | articles | fulltext | title         | title | 0       | NULL |    1 | Using where | 
    +----+-------------+----------+----------+---------------+-------+---------+------+------+-------------+ 
    1 row in set (0.00 sec) 

    但如果某个单词单词出现在至少全文的50%的行中,它会被列入停止字。对于大型数据集,使用这个操作最合适不过了----一个自然语言问询不会从一个1GB 的表每隔一行返回一次。对于小型数据集,它的用处可能比较小。不是大型的数据量,就不要用他,影响插入速度 

    7、mysql 5.6支持explain update/delete 

    mysql> explain update update_log_test set msg='gugu' where id=4; 
    +----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+ 
    | id | select_type | table           | type  | possible_keys | key     | key_len | ref   | rows | Extra       | 
    +----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+ 
    |  1 | SIMPLE      | update_log_test | range | PRIMARY       | PRIMARY | 4       | const |    1 | Using where | 
    +----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+ 
    1 row in set (0.01 sec) 

    mysql> explain delete from update_log_test  where id=4; 
    +----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+ 
    | id | select_type | table           | type  | possible_keys | key     | key_len | ref   | rows | Extra       | 
    +----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+ 
    |  1 | SIMPLE      | update_log_test | range | PRIMARY       | PRIMARY | 4       | const |    1 | Using where | 
    +----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+ 
    1 row in set (0.00 sec) 

    8、mysql5.6优化了合并索引 

    mysql> explain select * from update_log where date='2014-11-12' or time='14:00:00'; 
    +----+-------------+------------+-------------+---------------+-------------+---------+------+----------+---------------------------------------+ 
    | id | select_type | table      | type        | possible_keys | key         | key_len | ref  | rows     | Extra                                 | 
    +----+-------------+------------+-------------+---------------+-------------+---------+------+----------+---------------------------------------+ 
    |  1 | SIMPLE      | update_log | index_merge | date,i_time   | date,i_time | 4,4     | NULL | 10808103 | Using union(date,i_time); Using where | 
    +----+-------------+------------+-------------+---------------+-------------+---------+------+----------+---------------------------------------+ 
    1 row in set (0.01 sec) 

    mysql> explain select * from update_log where date='2014-11-12' union select * from update_log where time='14:00:00'; 
    +----+--------------+------------+------+---------------+--------+---------+-------+----------+-----------------------+ 
    | id | select_type  | table      | type | possible_keys | key    | key_len | ref   | rows     | Extra                 | 
    +----+--------------+------------+------+---------------+--------+---------+-------+----------+-----------------------+ 
    |  1 | PRIMARY      | update_log | ref  | date          | date   | 4       | const | 10807697 | NULL                  | 
    |  2 | UNION        | update_log | ref  | i_time        | i_time | 4       | const |      406 | Using index condition | 
    | NULL | UNION RESULT | <union1,2> | ALL  | NULL          | NULL   | NULL    | NULL  |     NULL | Using temporary       | 
    +----+--------------+------------+------+---------------+--------+---------+-------+----------+-----------------------+ 
    3 rows in set (0.00 sec) 

    实际测试2条sql,or的执行时间是union执行时间的两倍。 

     1、union all 不一定就比 or及in 快,要结合实际情况分析到底使用哪种情况。 
      2、对于索引列来最好使用union all,因复杂的查询【包含运算等】将使or、in放弃索引而全表扫描,除非你能确定or、in会使用索引。 
      3、对于只有非索引字段来说你就老老实实的用or 或者in,因为 非索引字段本来要全表扫描而union all 只成倍增加表扫描的次数。 


    Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;Union All:对两个结果集进行并集操作,包括重复行,不进行排序;  

    union因为要进行重复值扫描,所以效率低。 
    展开全文
  • SQL调优常用方法

    2018-10-19 11:53:00
    在使用DBMS时经常对系统的性能有非常高的要求:不能占用过多的系统内存和 CPU资源、要尽可能快的完成的数据库操作、要有尽可能高的系统吞吐量。如果系统开发出来不能满足要求的所有性能指标,则必须对系统进行调整,...

    在使用DBMS时经常对系统的性能有非常高的要求:不能占用过多的系统内存和 CPU资源、要尽可能快的完成的数据库操作、要有尽可能高的系统吞吐量。如果系统开发出来不能满足要求的所有性能指标,则必须对系统进行调整,这个工作被称为调优。绝定DBMS的性能的因素有两个因素:硬件和软件使用频率高的CPU、使用多处理器、加大内存容量、增加Cache、提高网络速度等这些都是非常有效的硬件调优方式,不过对硬件进行调优对系统性能的提高是有限的,如果有非常好的硬件条件但是如果编写的SQL质量非常差的话系统的性能并不会有明显的改善,而如果能对SQL语句进行充分的优化的话即使硬件条件稍差的话,系统性能的变化也是非常惊人的。硬件的调优涉及到非常多的内容,不是本节所能覆盖的,因此本节将主要讲解SQL的调优。

    SQL调优的基本原则
      "二八原理" 是一个普遍的真理,特别是在计算机的世界中表现的更加明显,那就是20%的代码的资源消耗占用了80%的总资源消耗。SQL语句也是一种代码,因此它也符合这个原理。在进行SQL调优的时候应该把主要精力放到这20%的最消耗系统资 源的SQL语句中,不要想把所有的SQL语句都调整到最优状态。
      很多DBMS都提供了非常好的工具用来分析系统中所有SQL语句资源消耗的工具,借助于这些工具发现占用系统资源排在前面的SQL语句,然后尝试对它们进行优化,优化后再次执行分析,迭代这一过程,直到系统中没有明显的系统资源消耗异常的SQL语句为止。

    索引
      索引是数据库调优的最根本的优化方法,很多优化手法都是围绕索引展开的,可以说索引是一切优化手法的“内功”,而所有的优化手法都是由索引衍化出来的招式而已。
      根据索引的顺序与数据表的物理顺序是否相同,可以把索引分成两种类型:聚簇索引,数据表的物理顺序与索引顺序相同;非聚簇索引,数据表的物理顺序与索引顺序不相同。下面,我们举例来说明一下聚集索引和非聚集索引的区别:
      字典的目录就是一种索引,因为通过目录我们可以很快的定位到要检索的内容,而不用从头到尾把字典翻一遍。汉语字典一般都至少提供两种目录,一种是拼音目录,一种是偏旁部首目录。汉语字典是按照拼音的顺序排列的,因此拼音目录就是聚集索引,而偏旁部首目录则是非聚集索引。应该在表中经常搜索的列或者按照顺序访问的列上创建聚簇索引。当创建聚簇索引时要需要每一个表只能有一个聚簇索引,因为表中数据的物理顺序只能有一个,而非聚集索引则可以创建多个。
      由于索引需要占据一定的存储空间,而且索引也会降低数据插入、更新和删除的速度,所以应该只创建必要的索引,一般是在检索的时候用的字段中创建索引。
      索引还会造成存储碎片的问题。当删除一条记录时将会导致对应的索引中的该记录的对应项为空,由于索引是采用B树结构存储的,所以对应的索引项并不会被删除,经过一段时间的增删改操作后,数据库中就会出现大量的存储碎片,这和磁盘碎片、内 存碎片产生原理是类似的,这些存储碎片不仅占用了存储空间,而且降低了数据库运行的速度。如果发现索引中存在过多的存储碎片的话就要进行“碎片整理”了,最方便的“碎片整理”手段就是重建索引,重建索引会将先前创建的索引删除然后重新创建索引,主流数据库管理系统都提供了重建索引的功能,比如REINDEX、REBUILD等,如果 使用的数据库管理系统没有提供重建索引的功能,可以首先用DROP INDEX语句删除索引,然后用ALTER TABLE语句重新创建索引。

    表扫描和索引查找
      一般地,系统访问数据库中的数据,可以使用两种方法:全表扫描和索引查找。
      全表扫描,就是指系统必须在数据表中逐条检索表中的每条记录,以检查该记录是否匹配检索条件。全表扫描有可能会造成巨大的性能损失,当然也有可能不会影响性能,这取决于表中的数据量,如果表中有上千万条甚至上亿条记录的话,全表扫描的速度会 非常慢,而如果表中只有几条、几十条记录的话表扫描的性能消耗就可以忽略不计了。当表中数据量比较小的时候,使用全表扫描非常有用。但是随着表中数据量的增加,全表扫描会导致系统性能严重下降。
      如果表中有索引并且待匹配条件符合索引的要求的话,DBMS就不会执行全表扫描,而是直接到索引中查找,这将大大加快检索的速度。
      DBMS中都有查询优化器,它会根据分布的统计信息生成该查询语句的优化执行规划,以提高访问数据的效率为目标,确定是使用全表扫描还是使用索引查找。注意并不是表中存在索引在进行检索的时候就会使用索引查找,如果使用不当检索的过程仍然会是采用全表扫描,这样索引就起不到效果了。

    优化手法
      下面将会列出了一些常用的优化手法,注意这些优化手法只是一些常规条件下的优化手法,具体的优化效果是与使用的DBMS以及数据的特点密切相关的,需要根据具体情况来使用不同的优化手法,如果使用不当的话有可能会适得其反。

    1、创建必要的索引
      在经常需要进行检索的字段上创建索引,比如经常要按照图书名称进行检索,那么就应该在图书名称字段上创建索引,如果经常要按照员工部门和员工岗位级别进行检索,那么就应该在员工部门和员工岗位级别这两个字段上创建索引。创建索引给检索带来的性能提升往往是巨大的,因此在发现检索速度过慢的时候应该首先想到的就是创建索引。

    2、使用预编译查询
      程序中通常是根据用户的输入来动态执行SQL语句,这时应该尽量使用参数化SQL,这样不仅可以避免SQL注入漏洞攻击,最重要数据库会对这些参数化SQL执行预编译,这样第一次执行的时候DBMS会为这个SQL语句进行查询优化并且执行预编译,这样以后再执行这个SQL的时候就直接使用预编译的结果,这样可以大大提高执行的速度。

    3、调整WHERE子句中的连接顺序

      DBMS一般采用自下而上的顺序解析WHERE子句,根据这个原理,表连接最好写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件写在WHERE子句的末尾。 
      比如下面的SQL语句性能较差:

    复制代码
    1 SELECT *
    2 FROM T_Person
    3 WHERE  FSalary > 50000
    4 AND  FPosition= 'MANAGER'
    5 AND  25 < (SELECT COUNT(*)
    6 FROM T_Manager
    7 WHERE FManagerId=2);
    复制代码

      我们将子查询的条件放到最前面,下面的SQL语句性能比较好:

    复制代码
    1 SELECT *
    2 FROM T_Person
    3 WHERE 
    4 25 < (SELECT COUNT(*) 
    5 FROM T_Manager
    6 WHERE FManagerId = 2)
    7 AND FSalary > 50000
    8 AND FPosition= 'MANAGER';
    复制代码

    4、SELECT语句中避免使用'*'
      SELECT *比较简单,但是除非确实需要检索所有的列,否则将会检索出不需要的列,这回增加网络的负载和服务器的资源消耗;即使确实需要检索所有列,也不要使用 SELECT *,因为这是一个非常低效的方法,DBMS在解析的过程中,会将*依次转换成所有的列名,这意味着将耗费更多的时间

    5、尽量将多条SQL语句压缩到一句SQL中
      每次执行SQL的时候都要建立网络连接、进行权限校验、进行SQL语句的查询优化、发送执行结果,这个过程是非常耗时的,因此应该尽量避免过多的执行SQL语句, 能够压缩到一句SQL执行的语句就不要用多条来执行。

    6、用Where子句替换HAVING子句
      避免使用HAVING子句,因为HAVING 只会在检索出所有记录之后才对结果集进行过滤。如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销。 HAVING 中的条件一般用于聚合函数的过滤,除此而外,应该将条件写在WHERE子句中。

    7、使用表的别名
      当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个列名上。这样就可以减少解析的时间并减少那些由列名歧义引起的语法错误。

    8、用EXISTS替代IN
      在查询中,为了满足一个条件,往往需要对另一个表进行联接,在这种情况下,使用EXISTS而不是IN通常将提高查询的效率,因为IN 子句将执行一个子查询内部的排序和合并。下面的语句2就比语句1效率更加高。

    复制代码
     1 --语句1:
     2 SELECT * FROM T_Employee
     3 WHERE FNumber> 0
     4 AND FDEPTNO IN (SELECT FNumber
     5 FROM T_Department
     6 WHERE FMangerName = 'Tome')
     7 
     8 --语句2:
     9 SELECT * FROM T_Employee EMP
    10 WHERE EMP.FNumber > 0
    11 AND EXISTS (SELECT 1
    12 FROM T_Department DEP
    13 WHERE DEP.FDEPTNO = EMP.FNumber
    14 AND DEP.FMangerName = 'Tome')
    复制代码

    9 、用表连接替换EXISTS
      通常来说,表连接的方式比EXISTS更有效率,因此如果可能的话尽量使用表连接替换EXISTS。下面的语句2就比语句1效率更加高。

    复制代码
     1 --语句1:
     2 SELECT * FROM T_Employee EMP
     3 WHERE EMP.FNumber > 0
     4 AND EXISTS (SELECT 1
     5 FROM T_Department DEP
     6 WHERE DEP.FDeptno = EMP.FNumber
     7 AND DEP.FKind = 'A')
     8 --语句2:
     9 SELECT FName FROM T_Department DEP,T_Employee EMP
    10 WHERE DEP.FDeptno = EMP.FNumber
    11 AND DEP.FKind = 'A';
    复制代码

    10、避免在索引列上使用计算 
      在WHERE子句中,如果索引列是计算或者函数的一部分,DBMS的优化器将不会使用索引而使用全表扫描。
      例如下面的SQL语句用于检索月薪的12倍大于两万五千元的员工:

    1 SELECT *
    2 FROM T_Employee
    3 WHERE FSalary * 12 >25000;

      由于在大于号左边的是FSalary与12的成绩表达式,这样DBMS的优化器将不会使用字段FSalary的索引,因为DBMS必须对T_Employee表进行全表扫描,从而计算 FSalary * 12 的值,然后与25000进行比较。将上面的SQL语句修改为下面的等价写法后DBMS将会使用索引查找,从而大大提高了效率:

    1 SELECT *
    2 FROM T_Employee
    3 WHERE FSalary >25000/12;

      同样的,不能在索引列上使用函数,因为函数也是一种计算,会造成全表扫描。下面的语句2就比语句1效率更加高。

    复制代码
    1 --语句1:
    2 SELECT *
    3 FROM T_Example
    4 WHERE ABS(FAmount)=300
    5 --语句2:
    6 SELECT *
    7 FROM T_Example
    8 WHERE FAmount=300 OR FAmount=-300
    复制代码

    11、用UNION ALL 替换UNION
      当SQL语句需要UNION两个查询结果集合时,即使检索结果中不会有重复的记录,如果使用UNION这两个结果集同样会尝试进行合并,然后在输出最终结果前进行排序。
      因此,如果检索结果中不会有重复的记录的话,应该用UNION ALL替代UNION,这样效率就会因此得到提高。下面的语句2就比语句1效率更加高。

    复制代码
     1 --语句1:
     2 SELECT ACCT_NUM, BALANCE_AMT
     3 FROM DEBIT_TRANSACTIONS1
     4 WHERE TRAN_DATE = '20010101'
     5 UNION
     6 SELECT ACCT_NUM, BALANCE_AMT
     7 FROM DEBIT_TRANSACTIONS2
     8 WHERE TRAN_DATE ='20010102';
     9 --语句2:
    10 SELECT ACCT_NUM, BALANCE_AMT
    11 FROM DEBIT_TRANSACTIONS1
    12 WHERE TRAN_DATE ='20010101'
    13 UNION ALL
    14 SELECT ACCT_NUM, BALANCE_AMT
    15 FROM DEBIT_TRANSACTIONS2
    16 WHERE TRAN_DATE = '20010102';
    复制代码

    12、避免隐式类型转换造成的全表扫描
      T_Person表的字符串类型字段FLevel为人员的级别,在FAge字段上建有索引。我们执行下面的SQL语句用于检索所有级别等于10的员工:

    1 SELECT FId,FAge,FName
    2 FROM T_Person
    3 WHERE FAge=10

      在这个SQL语句中,将字符串类型字段FLevel与数值10进行比较,由于在大部分数据库中隐式转换类型中数值类型的优先级高于字符串类型,因此DBMS会对FAge字段进行隐式类型转换,相当于执行了下面的SQL语句:

    1 SELECT FId,FAge,FName
    2 FROM T_Person
    3 WHERE TO_INT(FAge)=10;

      由于在索引字段上进行了计算,所以造成了索引失效而使用全表扫描。因此应将 SQL语句做如下修改:

    1 SELECT FId,FAge,FName
    2 FROM T_Person
    3 WHERE FAge='10';

    13、防止检索范围过宽
      如果DBMS优化器认为检索范围过宽,那么它将放弃索引查找而使用全表扫描。下面是几种可能造成检索范围过宽的情况:使用IS NOT NULL或者不等于判断,可能造成优化器假设匹配的记录数太多。 使用LIKE运算符的时候,"a%"将会使用索引,而"a%c"和"%c"则会使用全表扫描,因此"a%c"和"%c"不能被有效的评估匹配的数量。

    14、SQL语句尽量用大写
      对Oracle来说,Oracle总是先解析sql语句,把小写的字母转换成大写的再执行。

    15、利用with字句重用查询

      如获得工资大于平均工资的员工和工资信息:

    复制代码
     1 select * from (
     2 select employee_id,avg(salary) avg_salary
     3 from salary
     4 group by employee_id
     5 )t
     6 where t.avg_salary >(
     7 select avg(avg_salary) from (
     8 select employee_id,avg(salary) avg_salary
     9 from salary
    10 group by employee_id
    11 ));
    复制代码

    可以看到子查询:

    1 select employee_id,avg(salary) avg_salary
    2 from salary
    3 group by employee_id;

    被重复执行,通过with子句可以将该子查询独立出来,并重用其查询结果,如下所示:

    复制代码
    1 with employee_avg_salary as (
    2 select employee_id,avg(salary) avg_salary
    3 from salary
    4 group by employee_id)
    5 select * from employee_avg_salary t
    6 where t.avg_salary > (
    7 select avg(avg_salary) 
    8 from employee_avg_salary);
    复制代码

    转载于:https://www.cnblogs.com/asdyzh/p/9815647.html

    展开全文
  • Java性能调优常用方法

    2018-11-20 07:17:44
    Java应用的性能优化也是一个老生常谈的话题,但是只要我们深入的了解性能调优方法,走遍天下都不怕! 根据我的个人经验,将Java性能优化分为4个层级:应用层、数据库层、框架层、JVM 层。通过介绍Java性能诊断工具和...

    Java给大部分人的感觉就是慢,有严重的性能问题。其实程序慢的问题,与语言无关,与Java无关。Java应用的性能优化也是一个老生常谈的话题,但是只要我们深入的了解性能调优方法,走遍天下都不怕!

    根据我的个人经验,将Java性能优化分为4个层级:应用层、数据库层、框架层、JVM 层。通过介绍Java性能诊断工具和思路,总结出性能优化案例以供参考。

    Java性能优化分层模型

    根据我的分层,应用层、数据库层、框架层、JVM 层四个层,每层优化难度逐级增加,涉及的知识和解决的问题也会不同。比如应用层需要理解代码逻辑,通过Java线程栈定位有问题代码行等;数据库层面需要分析 SQL、定位死锁等;框架层需要懂源代码,理解框架机制;JVM 层需要对 GC 的类型和工作机制有深入了解,对各种 JVM 参数作用了然于胸。围绕Java性能优化,有两种最基本的分析方法:现场分析法和事后分析法。现场分析法通过保留现场,再采用诊断工具分析定位。现场分析对线上影响较大,部分场景(特别是涉及到用户关键的在线业务时)不太合适。事后分析法需要尽可能多收集现场数据,然后立即恢复服务,同时针对收集的现场数据进行事后分析和复现。

    性能诊断工具

    性能诊断一种是针对已经确定有性能问题的系统和代码进行诊断,还有一种是对预上线系统提前性能测试,确定性能是否符合上线要求。可以用各种性能压测工具(例如JMeter)进行测试。针对Java应用,性能诊断工具主要分为两层:OS层面和Java应用层面(包括应用代码诊断和GC诊断)。OS层面的诊断主要关注的是 CPU、Memory、I/O 三个方面。CPU诊断是对于CPU主要关注平均负载(Load Average),CPU使用率,上下文切换次数(Context Switch)。另外也可以通过top命令可以查看系统平均负载和CPU使用率。

    vmstat命令

    一般使用vmstat命令可以查看CPU的上下文切换次数,例如在linux环境下,输入“vmstat 1”,结果如下图:

    上下文切换次数发生的场景主要有如下几种:

    时间片用完,CPU 正常调度下一个任务;

    被其它优先级更高的任务抢占;

    执行任务碰到 I/O 阻塞,挂起当前任务,切换到下一个任务;

    用户代码主动挂起当前任务让出 CPU;

    多任务抢占资源,由于没有抢到被挂起;

    硬件中断。

    Java 线程上下文切换主要来自共享资源的竞争。一般单个对象加锁很少成为系统瓶颈,除非锁粒度过大。但在一个访问频度高,对多个对象连续加锁的代码块中就可能出现大量上下文切换,成为系统瓶颈。

    内存方面(Memory)

    从操作系统角度,内存关注应用进程是否足够,可以使用 free –m命令查看内存的使用情况。通过top命令可以查看进程使用的虚拟内存VIRT和物理内存RES,根据公式VIRT = SWAP + RES可以推算出具体应用使用的交换分区(Swap)情况,使用交换分区过大会影响Java应用性能,可以将swappiness值调到尽可能小。因为对于Java应用来说,占用太多交换分区可能会影响性能,毕竟磁盘性能比内存慢太多。

    I/O方面

    I/O包括磁盘I/O和网络I/O,一般情况下磁盘更容易出现I/O瓶颈。通过iostat可以查看磁盘的读写情况,通过CPU的I/O wait可以看出磁盘I/O是否正常。如果磁盘I/O一直处于很高的状态,说明磁盘太慢或故障,成为了性能瓶颈,需要进行应用优化或者磁盘更换。

    除了常用的top、ps、vmstat、iostat等命令,还有其他Linux工具可以诊断系统问题,如mpstat、tcpdump、netstat、pidstat、sar等。下面摘录了部分Linux系统不同设备类型的性能诊断工具。

    总结与建议

    性能调优同样遵循 2-8 原则,80%的性能问题是由 20%的代码产生的,因此优化关键代码事半功倍。同时,对性能的优化要做到按需优化,过度优化可能引入更多问题。对于 Java 性能优化,不仅要理解系统架构、应用代码,同样需要关注 JVM 层甚至操作系统底层。总结起来主要可以从以下几点进行考虑:

    基础性能的调优

    这里的基础性能指的是硬件层级或者操作系统层级的升级优化,比如网络调优,操作系统版本升级,硬件设备优化等。比如 F5 的使用和 SDD 硬盘的引入,包括新版本 Linux 在 NIO 方面的升级,都可以极大的促进应用的性能提升;

    数据库性能优化

    包括常见的事务拆分,索引调优,SQL 优化,NoSQL 引入等,比如在事务拆分时引入异步化处理,最终达到一致性等做法的引入,包括在针对具体场景引入的各类 NoSQL 数据库,都可以大大缓解传统数据库在高并发下的不足;

    应用架构优化

    引入一些新的计算或者存储框架,利用新特性解决原有集群计算性能瓶颈等;或者引入分布式策略,在计算和存储进行水平化,包括提前计算预处理等,利用典型的空间换时间的做法等;都可以在一定程度上降低系统负载;

    业务层面的优化

    技术并不是提升系统性能的唯一手段,在很多出现性能问题的场景中,其实可以看到很大一部分都是因为特殊的业务场景引起的,如果能在业务上进行规避或者调整,其实往往是最有效的。

    如果想学习Java工程化、高性能及分布式、深入浅出。性能调优、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级架构进阶群:180705916,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家

    展开全文
  • 关系数据库调优

    2013-09-15 16:11:49
    对于web应用开发,多数性能瓶颈均出现在数据库上,除了采用分布式架构或云处理(大公司基本上都是),更重要的是平时程序设计时要遵照一些规则,从根本上提高系统的性能,以下总结了一些常用的规则方法,仅供参考。...
  • 1.检查数据库空间使用情况,查看哪些表占用了比较大的磁盘空间 执行语句如下: select o.name, SUM(p.reserved_page_count) as reserved_page_count, SUM(p.used_page_count) as used_page_count, SUM( ...
  • oracle 常用调优方法

    2020-09-24 10:50:44
    oracle常用调优方法 Oracle数据库应用系统的调优主要包括十个方面: (1)、优化数据库内存; (2)、在Oracle共享池中固定应用程序代码; (3)、优化数据存储; (4)、优化数据排序的技术; (5)、优化SQL语句; (6)、...
  • 这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查询结果会被放到一个缓存中,这样,后续的相同的查询就不用操作表而直接访问缓存结果了。 这里最主要...
  • Oracle-常用调优方法

    千次阅读 2018-09-03 14:34:34
    oracle 常用调优方法 Oracle数据库应用系统的调优主要包括十个方面:(1)、优化数据库内存;(2)、在Oracle共享池中固定应用程序代码;(3)、优化数据存储;(4)、优化数据排序的技术;(5)、优化SQL语句;(6)、优化回...
  • MySQL常用调优方法

    2018-12-09 15:13:17
    我在平时工作的时候,总是会遇到大数据量的插入、修改或是查询的操作,所以在工作的时候积累了一些MySQL数据库调优方式,在这里与大家分享一下。 一、缓存   缓存是解决这类问题的一把手。它既可以加快整个...
  • oracle 常用调优方法

    2012-03-30 00:30:00
    Oracle数据库应用系统的调优主要包括十个方面:(1)、优化数据库内存;(2)、在Oracle共享池中固定应用程序代码;(3)、优化数据存储;(4)、优化数据排序的技术;(5)、优化SQL语句;(6)、优化回退段;(7)、优化索引;(8...
  • 问题描述:服务器报错Out of memory: Kill process (mysqld)内存溢出Out of memory 问题,这通常是因为某时刻应用程序大量请求内存导致系统内存不足造成的,这通常会触发 ...在整体的系统运行过程中,数据库服务...
  • ORACLE PLSQL性能调优方法文档分享,文档记录了PLSQL常用调优方法。PL/SQL Developer是一个集成开发环境,专门开发面向Oracle数据库的应用。PL/SQL也是一种程序语言,叫做过程化SQL语言(Procedural Language/...
  • DB2数据库的一些调优方法
  • 在测试工作中经常需要对数据库进行性能测试,以对数据库... 本文使用常用的性能测试工具LOADRUNNER,JAVA和专用数据库性能测试工具Benchmark,讨论数据库性能测试的不同方法,希望能抛砖引玉,寻找出更新更好的方法
  • 数据迁移后性能受到影响,需要将老数据库中keep到内存中的表在新库中keep到内存中,使用如下方法。 新库设置db_keep_cache_size为适当值,这个值的大小不能小于需要keep的表的大小。 查看老库中需要...
  • sql优化常用的几种方法你知道多少?要想了解sql优化常用的几种方法首先要先了解SQL是什么,那么我们就先从SQL是什么慢慢说起吧。一起接着往下看1、SQL是什么的缩写SQL是Structured Quevy Language(结构化查询语言)的...
  • 索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多的速度检索特定的行,尤其是在查询语句当中包含有MAX(),MIN()和ORDERBY这些命令的时候,性能提高更为明显。 那该对哪些字段建立索引呢? ...
  • 衡量指标有哪些? 1. 吞吐量和响应速度 分布式的高并发应用并不能把单次请求作为判断依据,它往往是一个统计结果。... 有些时候,虽然响应速度比较慢,但整个吞吐量却非常高,比如一些数据库的批量操作、一些
  • 最有效的方法之一是通过 Oracle 调优。它有大量的调整参数和技术来改进你的 Oracle 数据库的性能。 Oracle 调优是一个复杂的主题。关于调优可以写整整一本书,不过,为了改善 Oracle 数据库的性能,有一些基本的...
  • Oracle调优浅析

    2011-08-22 22:19:21
    我们在做开发时,常用到Oracle数据库来开发一些大型项目,如何优化Oracle来提高效率这是开发者都曾遇到或者将会遇到的问题。 现在我们就来一起研究研究Oracle调优的一些基本方法方法一:硬件调优。 硬件的更新...
  • Java性能调优(四)

    2017-04-24 10:28:00
    常用优化组件和方法 对象复用——“池”(数据库连接池) 并行替代串行、异步替代同步 负载均衡 时间换空间 空间换时间 缓存(EhCache、Memcached、Redis) Memcached 多线程,非阻塞IO复用的网络...
  • J2EE开发调优

    2018-09-24 10:28:47
    例如,小心使用继承、封装常用的业务方法及其相关工具、简化类结构、面向接口编程、尽量使用主要类型等。 尽可能使用数据库连接池。在使用JDBC访问数据时,尽可能使用PreparedStatement。 给Web容器配置合理的线程...
  • 查看Oracle执行计划的几种常用方法-系列1

    万次阅读 多人点赞 2014-08-30 22:08:15
    SQL的执行计划实际代表了目标SQL在Oracle数据库内部的具体执行步骤,作为调优,只有知道了优化...我们首先列出查看执行计划的一些常用方法: 1. explain plan命令 PL/SQL Developer中通过快捷键F5就可以查看目标SQ
  • 这里学习下HBase的调优Hbase查询优化作为NoSQL数据库,增删改查是其最基本的功能,其中查询是最常用的一项。设置Scan缓存HBase中Scan查询可以设置缓存,方法是setCaching(),这样可以有效的减少服务端与客户端的交互...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 179
精华内容 71
关键字:

数据库调优常用方法