MySQL优化

1.mysq 数据优化可以从以下几方面进行优化:
  1、sql及索引优化。 
  2 数据库表结构,根据数据设计查询最优的表结构。
  3,系统配置优化,对打开文件数和安全的限制。 
  4、硬件,选择最适合数据库的cpu,更快的IO,更大的内存,cpu不是越多越好, IO并不能减少锁的机制,也就是不能减少阻塞,所以说硬件的优化成本越高,效果最差。

2:  演示数据
  下载演示数据库网址:https://dev.mysql.com/doc/index-other.html
  查看数据库表结构网址:https://dev.mysql.com/doc/sakila/en/sakila-installation.html
  2.1登录下载数据库网址,下载sakila database的zip包,解压出现三个文件:sakila-data.sql、sakila-schema.sql、sakila.mwb
  2.2 创建数据库并插入数据
    shell> mysql -u root -p
    mysql> SOURCE C:/temp/sakila-db/sakila-schema.sql;
    mysql> SOURCE C:/temp/sakila-db/sakila-data.sql;
    mysql> USE sakila;
    mysql> SHOW TABLES;
    mysql> SELECT COUNT(*) FROM film;
    mysql> SELECT COUNT(*) FROM film_text;
3:SQL及索引优化
  1、show_query_log_file:慢查日志存储位置
  2、log_queries_not_use_indexes:是否把没有使用索引的查询记录到慢查询日志中
  3、long_query_time:超过多少秒的查询记录到慢查询日志中
    使用MySQL慢查日志对有效率问题的SQL进行监控
    show variables like 'slow_query_log';    //查看是否开启慢查日志
    命令行:
      show variables like 'slow_query_log';--查看开启状态
        set global slow_query_log=on;
      show variables like '%log%'; -- 看log_queries_not_using_indexes | OFF 这条记录
      --显示log_queries_not_using_indexes      off  没有使用索引的日志
        set global log_queries_not_using_indexes=on;
      show variables like 'long_query_time';--查询时间
        set  long_query_time=0;
      -- 查看慢日志具体目录
      show variables like 'slow%';
     进入慢日志文件:
      1)退出mysql模式,
      2)#> tail -50 /usr/local/var/mysql/Hadess-slow.log
      3)日志显示内容
        --执行SQL的内容
        SELECT * FROM store LIMIT 10;
        # Time: 2019-03-27T02:36:31.678927Z
        -- 执行SQL的主机信息
        # User@Host: root[root] @ localhost [127.0.0.1]  Id:     2
        -- 执行SQL的信息
        # Query_time(查询时间): 0.002786  Lock_time(锁定时间): 0.000148 Rows_sent(发送的行数): 3  Rows_examined(扫描的行数): 1032
        -- 执行SQL的时间
        SET timestamp=1553654191;
4:工具
  慢查询日志分析工具:1)mysqldumpslow ,2)pt-query-digest
  1.mysqldumpslow(mysql官方自带的,安装的时候就带有)
  2.mysqldumpslow -t 3 /home/mysql/data/mysql-slow.log  | more(输出排名前三的查询慢的日志)
  3.-s (可以规定慢查询日志以什么方式排序展示)
  #> mysqldumpslow -t 3 /usr/local/var/mysql/Hadess-slow.log | more
  
  Reading mysql slow query log from /usr/local/var/mysql/Hadess-slow.log
    Count: 1  Time=0.02s (0s)  Lock=0.00s (0s)  Rows=0.0 (0), root[root]@localhost
  set global slow_query_log=on
    Count: 2  Time=0.00s (0s)  Lock=0.00s (0s)  Rows=2.0 (4), root[root]@localhost
  show variables like 'S'
Count: 1  Time=0.00s (0s)  Lock=0.00s (0s)  Rows=23.0 (23), root[root]@localhost
   show tables

5:通过explain查询和分析SQL的执行计划
  -- example https://blog.csdn.net/why15732625998/article/details/80388236
  -- example https://www.cnblogs.com/galengao/p/5780958.html
  explain返回各列的含义
    select_type:
      1)SIMPLE 简单的select查询,查询中不包含子查询或者UNION
      2)PRIMARY 查询中若包含任何复杂的子部分,最外层查询则被标记为PRIMARY
      3)SUBQUERY 在SELECT或WHERE列表中包含了子查询
      4)DERIVED 在FROM列表中包含的子查询被标记为DERIVED(衍生),MySQL会递归执行这些子查询,把结果放在临时表中
      5)UNION 若第二个SELECT出现在UNION之后,则被标记为UNION:若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
      6)UNION RESULT 从UNION表获取结果的SELECT
    table:显示这一行的数据是关于哪张表的
    type:
      从最好到最差依次是:system > const > eq_ref > ref > range > index > all
      这是重要的列,显示连接使用了何种类型。从最好的到最差的连接类型为const/eq_reg/ref/range/index和ALL
      1)system 表只有一行记录(等于系统表),这是const类型的特列,平时不会出现,这个也可以忽略不计
      2)const 表示通过索引一次就找到了,const用于比较primary key 或者unique索引。因为只匹配一行数据,所以很快。如将主键置于where列表中,MySQL就能将该查询转换为一个常量
      3)eq_ref 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
      4)ref 非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它返回所有匹配某个单独值的行,
          然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。
      5)range 只检索给定范围的行,使用一个索引来选择行,key列显示使用了哪个索引,一般就是在你的where语句中出现between、< 、>、in等的查询,这种范围扫描索引比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。
      6)index Full Index Scan,Index与All区别为index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小。
        (也就是说虽然all和Index都是读全表,但index是从索引中读取的,而all是从硬盘读取的)
      7)Full Table Scan 将遍历全表以找到匹配的行 
      
    possiable_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。
    key:实际使用的索引,如果为null,则没有使用索引
    key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度,在不损失精确性的情况下,长度越短越好。
            key_len显示的值为索引字段的最大可能长度,并         非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。
    ref:显示索引的那一列被使用了,如果可能的话,最好是一个常数。哪些列或常量被用于查找索引列上的值。 
    rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数,也就是说,用的越少越好 
    Extra:包含不适合在其他列中显式但十分重要的额外信息
      1)Using filesort(九死一生)
        说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。
        MySQL中无法利用索引完成的排序操作称为“文件排序”。 
      2)Using temporary(十死无生)
        使用了用临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于排序order by和分组查询group by。
      3)Using index(发财了)
        表示相应的select操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错。如果同时出现using where,表明索引被用来执行索引键值的查找;如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。
      4)Using where
        表明使用了where过滤
      5)Using join buffer
        表明使用了连接缓存,比如说在查询的时候,多表join的次数非常多,那么将配置文件中的缓冲区的join buffer调大一些。
      6)impossible where
        where子句的值总是false,不能用来获取任何元组
      7)select tables optimized away
        在没有GROUPBY子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。
      8)distinct
        优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作
    filtered:
      如果你用EXPLAIN EXTENDED将会展示出这列filtered(MySQL5.7缺省就会输出filtered),它指返回结果的行占需要读到的行(rows列的值)的百分比。按说filtered是个非常有用的值,因为对于join操作,前一个表的结果集大小直接影响了循环的次数。但是我的环境下测试的结果却是,filtered的值一直是100%,也就是说失去了意义。
  
6:具体sql语句优化
  1)Count和Max的优化
    Max的优化:针对max使用的字段设置索引;
    -- 创建索引
    CREATE INDEX idx_paydate on payment(payment_date);
    COUNT的优化:
      SELECT COUNT(release_year = '2006' OR NULL) AS A,
      COUNT(release_year = '2007' OR NULL) AS FROM film;
  2)子查询的优化
    通常情况下,需要把子查询优化为join查询。
    子查询优化 改为 join 连接查询时,关注两表之间 是否是一对多的关系,若有,则需要去重distinct。
    用连接的方式进行查询可能会导致数据重复,
    如:select t.id from t join t1 on t.id = t1.tid ,
    但是通过子查询就只有一条数据了:select * from t where t.id in (select ti.tid from ti);可以通过distinct去重;
  3)Group by的优化
    -- 优化之前的GROUP BY
    EXPLAIN
    SELECT actor.first_name,actor.last_name,COUNT(*)AS num
    FROM film_actor
    INNER JOIN actor USING(actor_id)
    GROUP BY film_actor.actor_id;
    -- 优化之后的GROUP BY
    EXPLAIN
    SELECT actor.first_name,actor.last_name,c.ctn
    FROM actor
    INNER JOIN
      (SELECT actor_id,COUNT(*)AS ctn 
	      FROM film_actor 
	      GROUP BY film_actor.actor_id)
    AS C USING(actor_id);
    4)limit的优化
      limit会使用Filesorts这样造成大量的IO问题;
      例如:select  film_id , description from salika.film order by title limit 500,5;
      分析:当limit 后面的数据越大,IO越高,性能越差;可以使用主键排序进行优化,避免过多的扫描;
      优化:select film_id , description from sakila.film where film_id >=500 and film_id <= 505 order by film_id limit 1,5;
      优化limit查询
        优化步骤1:使用有索引的列或这件进行order by操作
          select film_id ,description from sakila.film order by film_id limit 50,5;
        优化步骤2:记录上次返回的主键,在下次查询时用 主键过滤(避免了数据量大时扫描过多的记录)
          select film_id ,description from sakila.film where film_id >55 and film_id<=60 order by film_id
    5) 索引Index的优化
      索引的优点:
        提高查询的效率:select
      索引的缺点:
        降低写入的效率:insert、update、delete
      索引存在的目的是为了加快查询的效率,不过不是索引越多越好,建立索引要适当才好。
      5.1)选择合适的索引列
        5.1.1)在where,group by,order by,on从句中出现的列
        5.1.2)索引字段越小越好(因为数据库的存储单位是页,一页中能存下的数据越多越好 );
        5.1.3)离散度大得列放在联合索引前面
          select count(distinct customer_id), count(distinct staff_id) from payment;
          查看离散度 通过统计不同的列值来实现 count越大 离散程度越高
          select count(distinct customer_id), count(distinct staff_id) from payment;
          是index(sftaff_id,customer_id)好?还是index(customer_id,staff_id)好呢?
          由于customer_id的离散度更大,所以应该采用ndex(customer_id,staff_id)
          计算离散度:
            SELECT COUNT(DISTINCT customer_id),COUNT(DISTINCT staff_id) FROM payment;
      5.2)索引的维护及优化
        5.2.1) 重复索引和冗余索引
          重复索引是指相同的列已以相同的的顺序建立的同类索引,类似:
            CREATE TABLE test(
              id INT NOT NULL PRIMARY KEY,
              name VARCHAR(20) NOT NULL,
              UNIQUE(ID)
            )ENGINE=INNODB;
            其中id就是建立了重复的索引。
          -- 查找重复及冗余索引
          USE information_schema;
          DESC STATISTICS;
          SELECT * FROM STATISTICS;

          SELECT a.TABLE_SCHEMA AS '数据名'
	              ,a.TABLE_NAME AS '表名'
	               ,a.INDEX_NAME AS '索引1'
	              ,b.INDEX_NAME AS '索引2'
	        FROM STATISTICS AS a 
	        JOIN STATISTICS AS b
	        ON a.TABLE_SCHEMA = b.TABLE_SCHEMA
	        AND a.TABLE_NAME = b.TABLE_NAME
	        AND a.SEQ_IN_INDEX = b.SEQ_IN_INDEX
	        AND a.COLUMN_NAME = b.COLUMN_NAME
	        WHERE a.SEQ_IN_INDEX =1  AND a.INDEX_NAME<>b.INDEX_NAME;
	     5.2.2)工具检查重复的索引
	        pt-duplicate-key-checker工具检查重复的索引,然后删除重复的索引
       5.2.3)索引的维护及优化
          mysql中只能通过分析慢查日志配置pt-index-usage工具进行索引使用情况的分析,看哪些索引不常用,从而删除;
      6) MySQL数据库优化
        6.1)选择合适的数据类型
          6.1.1)使用可存下数据的最小的数据类型
          6.1.2)使用简单地数据类型,Int

 

你可能感兴趣的:(MySQL)