如何正确高效使用mysql数据库的索引--SQL查询优化

如何正确高效使用mysql数据库的索引

    • 1. 如何获取性能有问题的SQL
    • 2. 使用慢查询日志获取有性能问题的SQL
          • 慢查询日志设置参数
          • 常用的慢查询分析工具(mysqldumpslow)
          • 常用的慢查询分析工具(pt-query-digest)
    • 3.如何实时获取有性能问题的SQL
    • 4.查询速度为什么会慢
          • MYSQL服务器处理查询请求的整个过程:
          • 查询缓存对性能的影响
          • SQL解析预处理及生成执行计划
          • MYSQL优化器可优化的SQL类型
    • 5. 如何确定查询处理各个阶段所消耗的时间
    • 6. 特定SQL的优化查询
    • 7. 相关文章

1. 如何获取性能有问题的SQL

  • 通过用户反馈获取存在性能问题的SQL
  • 通过慢查日志获取存在性能问题的SQL
  • 实时获取存在性能问题的SQL

2. 使用慢查询日志获取有性能问题的SQL

  • 慢查询日志设置参数
  1. slow_query_log 启动停止记录慢查日志,set global slow_query_log=on
  2. slow_query_log_file 指定慢查日志的存储路径及文件,默认情况下保存在Mysql的数据目录中,建议分别存储在不同目录中
  3. long_query_time 指定记录慢查日志SQL执行时间的伐值,单位:s,默认为10s,通常改为0.001秒(1毫秒)比较合适
  4. log_query_not_using_indexes 是否记录未使用索引的SQL
  • 常用的慢查询分析工具(mysqldumpslow)
  1. 汇总除查询条件外其他完全相同的sql,并将分析结果按照参数中所指定的顺序输出。
  2. mysqldumpslow -s r -t 10 slow-mysql.log
    其中,
    -s order(c,t,l,r,at,al,ar)指定按照那种顺序输出结果,c:总次数,t:总时间,l:锁的时间,r:总数据行,at,ar,al:平均总次数,平均总行数,平均锁的时间
    -t top 指定取前几条作为输出结果
  • 常用的慢查询分析工具(pt-query-digest)

3.如何实时获取有性能问题的SQL

  • SELECT id,user,host,DB,command,time,state,info FROM information_schema.PROCESSLIST WHERE TIME>60,此SQL用于查询当前服务器中查询时间超过60s的SQL,TIME值可根据实际情况修改

4.查询速度为什么会慢

  • MYSQL服务器处理查询请求的整个过程:
  1. 客户端发送SQL请求给服务器
  2. 服务器查询是否可以在查询缓存中命中该SQL,命中则直接返回结果,未命中则进入下一阶段
  3. 服务器进行SQL解析,预处理,再由优化器生成对应的执行计划
  4. 根据执行计划,调用存储引擎API来查询数据
  5. 将结果返回给客户端
  • 查询缓存对性能的影响
  1. 优先检查这个查询是否命中查询缓存中的数据
  2. 查询缓存是通过一个对大小写敏感的哈希实现的,Hash查找只能进行全值匹配,只有当前查询玩完全匹配缓存中的查询时,才能命中缓存,若查询命中,则校验用户权限,权限通过后直接返回结果,否则进入下一个阶段。
  3. query_cache_type 设置查询缓存是否可用
- ON:开启查询缓存
- OFF:关闭查询缓存
- DEMAND:表示只有在查询语句中使用SQL_CACHE和SQL_NO_CACHE来控制是否需要缓存
  1. query_cache_size 设置查询缓存的内存大小,必须是1024整倍数
  2. query_cache_limit 设置查询缓存可用存储的最大值,超过这个值则不会被缓存
  3. query_cache_wlock_invalidate 设置数据表被锁后是否返回缓存中的数据,默认关闭
  4. query_cache_min_res_unit 设置查询缓存分配的内存块最小单位
  5. 如果数据库有较频繁的读写操作,建议将查询缓存关闭,将query_cache_type设置为OFF,将query_cache_size设置为0
  6. 当查询缓存未启用或者查询未命中缓存,则进入下一个阶段,将SQL转换成执行计划
  • SQL解析预处理及生成执行计划
  1. MYSQL按照执行计划和存储引擎进行交互,包括多个子阶段
- 解析SQL,预处理,优化SQL执行计划。
- 语法解析是通过关键字对MYSQL语句进行解析,并生成一颗对应的“解析树”,MYSQL解析器将使用MYSQL语法规则验证和解析查询,包括语法是否使用了正确的关键字,关键字的顺序是否正确等;
- 预处理阶段则进一步检查解析数是否合法,检查查询中所涉及的表和数据列存在,及名字和别名是否存在歧义等;
- 语法检查通过了,查询优化器就可以生成查询计划了
  1. 会造成MYSQL生成错误的执行计划的原因
- 统计信息不准
- 执行计划中的成本估算不等同于实际的执行计划的成本,因为MYSQL服务器层并不知道哪些页面在内存中,哪些页面在磁盘上,哪些页面需要顺序读取,哪些页面需要随机读取
- MYSQL优化器所认为的最优可能与你所认为的最优不一样,MYSQL基于其成本模型选择最优的执行计划,有时候这并不是最快的执行计划
- MYSQL不会考虑其他并发的查询,这可能会影响当前查询的速度
- MYSQL有时会基于一些固定的规则来生成执行计划
- MYSQL不会考虑不受其控制的成本,比如执行存储过程、用户自定义的函数
  • MYSQL优化器可优化的SQL类型
  1. 重新定义表的关联顺序,优化器会根据表的信息决定表的关联顺序
  2. 将外连接转换为内连接
  3. 使用等价变化规则,例如(5 = 5 and a>5)将被改写为a>5
  4. 优化count(),min(),max()
  5. 将一个表达式转化为常数表达式
  6. 子查询优化
  7. 提前终止查询
  8. 对in()条件进行优化

5. 如何确定查询处理各个阶段所消耗的时间

  • 使用 profile
  1. set profiling = 1,启动profile,这是一个session级的配置
  2. 执行查询
  3. show profiles;查看每一个查询所消耗的总时间的信息
  4. show profile for query N;N为上一条命令显示的QUERY_ID值,查询每个阶段所消耗的时间
  • 使用performance_schema

6. 特定SQL的优化查询

  • 如何优化not in 或 <> 查询
    例如:
    SELECT customer_id,first_name,lst_name,email
    FROM customer
    WHERE customer_id
    NOT IN (SELECT customer_id FROM payment)
    优化后:
    SELECT customer_id,first_name,lst_name,email
    FROM customer a
    LEFT JOIN payment b ON a.customer_id = b.customer_id
    WHERE b.customer_id IS NULL
  • 使用汇总表优化查询
    SELECT COUNT(*) FROM product_comment WHERE product_id = 999,如果表中有上亿条记录,统计就会很慢
    汇总表就是提前以要统计的数据进行汇总并记录到表中以备后续的查询使用

7. 相关文章

如何正确高效使用mysql的索引–索引优化策略
如何正确高效使用mysql的索引——Btree索引和Hash索引

你可能感兴趣的:(数据库)