面试被问mysql性能优化,你知道别人都是怎么回答的吗,看完这篇保你成功!!!

面试被问mysql性能优化,你知道别人都是怎么回答的吗,看完这篇保你成功!!!

    • 影响性能的相关因素
      • 商业需求对性能的影响
      • 系统架构及实现对性能的影响
      • Query 语句对系统性能的影响
      • Schema 设计对系统的性能影响
      • 硬件环境对系统性能的影响
    • 合理利用锁机制优化 My SQL
      • MyISAM 表锁优化建议
        • 缩短锁定时间
        • 分离能并行的操作
        • 合理利用读写优先级
    • Query优化
      • 法宝
      • 工具
        • 示例
        • Show profile详解
          • show profile的常用查询参数
        • 高能!
      • 合理设计并利用索引合
      • Join 优化思路
      • ORDER BY 排序算法
        • 最佳实践
        • 扩展:
      • ORDER BY 调优
      • GROUP BY 优化
        • 用松散(Loose)索引扫描实现 GROUP BY
          • 利用到松散索引扫描实现 GROUP BY,需要至少满足以下几个条件:
        • 使用紧凑(Tight)索引扫描实现 GROUP BY
          • 紧凑和松散索引扫描的区别
        • 使用临时表实现 GROUP BY
        • 小结
      • Innodb表锁优化建议
    • Schema 设计的性能优化
      • 三大范式
      • 高效的模型设计
      • 合适的数据类型
    • 存储引擎优化
      • Myisam 索引缓存参数
        • Myisam 表读取缓存优化
        • Myisam 其他优化
      • Innodb优化
        • Innodb 缓存优化
        • Innodb 事务优化
        • Innodb数据存储优化
        • 分散 IO 提升磁盘响应
        • 其他优化
    • InnoDB如何保持数据的一致性呢?MVCC了解下?
    • mysql 为什么会存在间隙锁,是来解决什么问题的呢,有什么缺陷吗
  • 扩展
      • mysql是如何 死锁检测、事务大小判断的呢 ?你知道吗
          • mysql 有关架构该怎么优化。整理中。。。敬请关注

影响性能的相关因素

商业需求对性能的影响

  • 不合理需求造成资源投入产出比过低
  • 无用功能堆积使系统过度复杂影响整体性能

系统架构及实现对性能的影响

  • 数据库中存放的数据是否合理
  • 是否合理的利用了应用层 Cache 机制
  • 对数据库的过渡依赖
  • 过度理想化系统的用户体验,使大量非核心业务消耗过多的资源,如大量不需要实时更新的数据 做了实时统计计算

Query 语句对系统性能的影响

  • Sql是否合理

Schema 设计对系统的性能影响

  • 如何根据业务合理设计Schema

硬件环境对系统性能的影响

  • CPU、磁盘、内存
  • 理性看待,并不是硬件资源越好,性能就越好

合理利用锁机制优化 My SQL

MyISAM 表锁优化建议

缩短锁定时间

  • 尽两减少大的复杂 Query,将复杂 Query 分拆成几个小的 Query 分布进行
  • 尽可能的建立足够高效的索引,让数据检索更迅速
  • 尽量让 MyISAM 存储引擎的表只存放必要的信息,控制字段类型
  • 利用合适的机会优化 MyISAM 表数据文件

分离能并行的操作

  • Concurrent Insert(并发插入)的特性
    当concurrent_insert=0时,不允许并发插入功能。
  • 当concurrent_insert=1时,存储引擎的表数据文件的中间部分存在空闲空间时,可以进行从文件尾部进行ConcurrentInsert。
  • 当concurrent_insert=2时,无论是否存在空闲空间时,都允许在数据文件结尾并发插入。

合理利用读写优先级

  • 要优先保证查询性能的话,我们可以通过设置系统参数选项 low_priority_updates=1,将写的优先级设置为比读的优先级低、一般情况下concurrent_insert结合使用

面试被问mysql性能优化,你知道别人都是怎么回答的吗,看完这篇保你成功!!!_第1张图片
面试被问mysql性能优化,你知道别人都是怎么回答的吗,看完这篇保你成功!!!_第2张图片
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dI3iL3TR-1588946884165)(media/15889432895273/15889440607388.jpg)]

  • Table_locks_immediate:产生表级锁定的次数
  • Table_locks_waited:出现表级锁定争用而发生等待的次数
  • Innodb_row_lock_current_waits:当前正在等待锁定的数量
  • Innodb_row_lock_time:从系统启动到现在锁定总时间长度
  • Innodb_row_lock_time_avg:每次等待所花平均时间
  • Innodb_row_lock_time_max:从系统启动到现在等待最常的一次所花的时间
  • Innodb_row_lock_waits:系统启动后到现在总共等待的次数

Query优化

法宝

  • 优化更需要优化的 Query
  • 定位优化对象的性能瓶颈
  • 明确的优化目标
  • 从 Explain 入手
  • 多使用 profile
  • 永远用小结果集驱动大的结果集
  • 尽可能在索引中完成排序
  • 只取出自己需要的 Columns
  • 仅仅使用最有效的过滤条件
  • 尽可能避免复杂的 Join 和子查询

工具

  • 充分利用 Explain和 Profile

示例

面试被问mysql性能优化,你知道别人都是怎么回答的吗,看完这篇保你成功!!!_第3张图片
面试被问mysql性能优化,你知道别人都是怎么回答的吗,看完这篇保你成功!!!_第4张图片

  • show status like ‘table%’
  • show status like ‘innodb_row_lock%’
  • set profiling=1
  • select * from jackl_t2 where year_col =11776576109023
  • show profiles
  • show profile cpu,block io for query 10

Show profile详解

show profile的常用查询参数
  • ALL:显示所有的开销信息
  • BLOCK IO:显示块IO开销
  • CONTEXT SWITCHES:上下文切换开销
  • CPU:显示CPU开销信息
  • IPC:显示发送和接收开销信息
  • MEMORY:显示内存开销信息
  • PAGE FAULTS:显示页面错误开销信息
  • SOURCE:显示和Source_function,Source_file,Source_line相关的开销信息
  • SWAPS:显示交换次数开销信息

高能!

  • converting HEAP to MyISAM:查询结果太大,内存不够,数据往磁盘上搬了
  • Creating tmp table:创建临时表。先拷贝数据到临时表,用完后再删除临时表
  • Copying to tmp table on disk:把内存中临时表复制到磁盘上,危险!!!
  • locked。
    如果在show profile诊断结果中出现了以上4条结果中的任何一条,则sql语句需要优化。

合理设计并利用索引合

  • 选择合适的索引及合理的使用

Join 优化思路

  • 尽可能减少 Join 语句中的 Nested Loop 的循环总次数-永远用小结果集驱动大的结果集
  • 优先优化 Nested Loop 的内层循环
  • 保证 Join 语句中被驱动表上 Join 条件字段已经被索引
  • 当无法保证被驱动表的 Join 条件字段被索引且内存资源充足的前提下,不要太吝惜 Join Buffer 的设置

ORDER BY 排序算法

最佳实践

  • 利用索引实现数据排序的方法是 MySQL 中实现结果集排序的最佳做法,可以完全避免因为排序 计算所带来的资源消耗。

扩展:

  • 默认一直有的排序算法。取出满足过滤条件的用于排序条件的字段以及可以直接定位到行数据的行指针信息,在 Sort Buffer 中进行实际的排序操作,然后利用排好序之后的数据根据行指针信息返回表中取得客户端请 求的其他字段的数据,再返回给客户端

  • MySQL4.1 版本才开始增加的改进版排序算法。根据过滤条件一次取出排序字段以及客户端请求的所有其他字段的数据,并将不需要排序的字 段存放在一块内存区域中,然后在 Sort Buffer 中将排序字段和行指针信息进行排序,最后再利用 排序后的行指针与存放在内存区域中和其他字段一起的行指针信息进行匹配合并结果集,再按照顺 序返回给客户端

  • 扩展的两种算法优先使用哪种呢,是通过max_length_for_sort_data参数控制

ORDER BY 调优

####当我们无法避免排序操作的时候,我们又该如何来优化呢?

  • 加大 max_length_for_sort_data 参数的设置。当我们所有返回字段的最大长度小于这个参数值的时候, MySQL 就会选择改进后的排序算法,反之,则选择老式的算法
  • 去掉不必要的返回字段
  • 增大 sort_buffer_size 参数设置。增大 sort_buffer_size 并不是为了让 MySQL 可以选择改进版的排序算法,而是为了让 MySQL 可以尽量减少在排序过程中对需要排序的数据进行分段,因为这样会造成 MySQL 不得不使用临时表 来进行交换排序

GROUP BY 优化

用松散(Loose)索引扫描实现 GROUP BY

利用到松散索引扫描实现 GROUP BY,需要至少满足以下几个条件:
  • GROUP BY 条件字段必须在同一个索引中最前面的连续位置
  • 在使用 GROUP BY 的同时,只能使用 MAX 和 MIN 这两个聚合函数
  • 如果引用到了该索引中 GROUP BY 条件之外的字段条件的时候,必须以常量形式存在

使用紧凑(Tight)索引扫描实现 GROUP BY

紧凑和松散索引扫描的区别

主要在于他需要在扫描索引的时候,读取所有 满足条件的索引键,然后再根据读取恶的数据来完成 GROUP BY 操作得到相应结果

使用临时表实现 GROUP BY

小结

  • 尽可能让 MySQL 可以利用索引来完成 GROUP BY 操作,当然最好是松散索引扫描的方式最佳。 在系统允许的情况下,我们可以通过调整索引或者调整 Query 这两种方式来达到目的
  • 当无法使用索引完成 GROUP BY 的时候,由于要使用到临时表且需要 filesort,所以我们必须 要有足够的 sort_buffer_size 来供 MySQL 排序的时候使用,而且尽量不要进行大结果集的 GROUP BY 操作,因为如果超出系统设置的临时表大小的时候会出现将临时表数据 copy 到磁盘上面再进行 操作,这时候的排序分组操作性能将是成数量级的下降

Innodb表锁优化建议

  • 尽可能让所有的数据检索都通过索引来完成,从而避免 Innodb 因为无法通过索引键加锁而升级 为表级锁定
  • 合理设计索引,让 Innodb 在索引键上面加锁的时候尽可能准确,尽可能的缩小锁定范围,避免 造成不必要的锁定而影响其他 Query 的执行
  • 尽可能减少基于范围的数据检索过滤条件,避免因为间隙锁带来的负面影响而锁定了不该锁定 的记录
  • 尽量控制事务的大小,减少锁定的资源量和锁定时间长度
  • 在业务环境允许的情况下,尽量使用较低级别的事务隔离,以减少 MySQL 因为实现事务隔离级 别所带来的附加成本

Schema 设计的性能优化

三大范式

第一范式:要求有主键,并且要求每一个字段原子性不可再分

第二范式:要求所有非主键字段完全依赖主键,不能产生部分依赖

第三范式:所有非主键字段和主键字段之间不能产生传递依赖

对于基于性能的数据库Schema设计,我们并不能完全以规范化范式理论来作为唯一的指导。在设计过程中,应该从实际需求出发,以性能提升为根本目标来展开设计工作,很多时候为了尽可能提高性能,我们必须做反范式设计

高效的模型设计

  • 适度冗余 - 让 Query 尽两减少 Join
  • 大字段垂直分拆 - summary 表优化
  • 大表水平分拆 - 基于类型的分拆优化
  • 统计表 - 准实时优化

合适的数据类型

  • 通过选用更“小”的数据类型减少存储空间,使查询相同数据需要的 IO 资源降低
  • 通过合适的数据类型加速数据的比较

存储引擎优化

Myisam 索引缓存参数

  • key_buffer_size索引缓存大小
    这个参数用来设置整个 MySQL 中的常规 Key Cache 大小。一般来说,如果我们的 MySQL 是运行 在 32 位平台纸上,此值建议不要超过 2GB 大小。如果是运行在 64 位平台纸上则不用考虑此限制,但 也最好不要超过 4GB

  • key_buffer_block_size索引缓存中的 Cache Block Size
    在 Key Cache 中的所有数据都是以 Cache Block 的形式存在,而 key_buffer_block_size 就是设置每个 Cache Block 的大小,实际上也同时限定了我们将 “.MYI”文件中的 Index Block 被读入时候的 File Block 的大小

  • key_cache_division_limit LRU 链表中的 Hot Area 和 Warm Area 分界值
    第一部分用来存放使 用比较频繁的 Hot Cacke Lock(Hot Chain)被成为 Hot Area
    第二部分则用来存放使用 不是太频繁的 Warm Cache Block(Warm Chain)被成为 Warm Area。
    目的主要是为 了保护使用比较频繁的 Cache Block 更不容易被换出。而 key_cache_division_limit 参数则是 告诉MySQL该如何划分整个Cache Chain划分为Hot Chain和 Warm Chain 两部分,参数值为 Warm Chain 占整个 Chain 的百分比值。设置范围 1~100,系统默认为 100,也就是只有 Warm Chain

  • key_cache_age_threshold控制 Cache Block 从 Hot Area 降到 Warm Area 的限制key_cache_age_threshold参数控制Hot Area中的Cache Block何时该被降级到Warm Area中。 系统默认值为 300,最小可以设置为 100。值越小,被降级的可能性越大

Myisam 表读取缓存优化

  • read_buffer_size,以 Sequential Scan 方式扫描表数据时候使用的 Buffer一般来说,可以尝试适当调大此参数看是否能够改善全表扫描的性能。在不同的平台上可能会 有不同的表现,这主要与OS 级别的文件系统IO 大小有关。所以该参数的设置最好是在真实环境 上面通过多次更改测试调整,才能选找到一个最佳值。
  • read_rnd_buffer_size,进行 RandomScan 的时候使用的 Buffer一般来说,read_rnd_buffer_size 值的适当调大,对提高 ORDER BY 操作的性能有一定的效果

Myisam 其他优化

  • optimize 碎片整理优化
  • 设置myisam_max_[extra]_sort_file_size 足够大,对 REPAIR TABLE 的效率可能会有较大改善
  • 在执行 CREATE INDEX 或者 REPAIR TABLE 等需要大的排序操作的之前可以通过调整 session 级 别的 myisam_sort_buffer_size 参数值来提高排序操作的效率
  • 通过打开delay_key_write功能,减少IO同步的操作,提高写入性能
  • 通过调整bulk_insert_buffer_size来提高 INSERT…SELECT…这样的 bulk insert 操作的整 体性能,LOAD DATA INFILE…的性能也可以得到改善。当然,在设置此参数的时候,也不应该一味 的追求很大,很多时候过渡追求极端反而会影响系统整体性能,毕竟系统性能是从整体来看的,而不能仅仅针对某一个或者某一类操作

Innodb优化

Innodb 缓存优化

  • Innodb_buffer_pool_size参数的合理设置
  • Innodb_log_buffer_size参数的合理设置
  • Double Write Buffer
    Innodb 所使用的一种较为独特的文件 Flush 实现技术,主要做用是为了通 过减少文件同步次数提高 IO 性能的情况下,提高系统 Crash 或者断电情况下数据的安全性,避免写入的 数据不完整
  • Adaptive Hash Index
    为了提高 Buffer Pool 中的数据 的访问效率,说的更浅显一点就是给 Buffer Pool 中的数据做的索引。所以,Innodb 在具有大容量内存 (可以设置大的 Buffer Pool)的主机上,对于其他存储引擎来说,会存在一定的性能优势

Innodb 事务优化

  • 选择合适的事务隔离级别

  • 事务与IO的关系及优化( innodb_flush_log_at_trx_commit)
    innodb_flush_log_at_trx_commit = 0,InnoDB中的Log Thread每隔1秒钟会将log buffer中的数据写入文件,同时还会通知文件系统进行与文件同步的flush操作,保证数据确实已经写入磁盘。但是,每次事务的结束(COMMIT或是ROLLBACK)并不会触发Log Thread将Log Buffer中的数据写入文件。所以,当设置为0时,在MySQL Crash和OS Crash或主机断电之后,最极端的情况是丢失1秒的数据变更。innodb_flush_log_at_trx_commit = 1,这也是InnoDB的默认设置。每次事务的结束都会触发Log Thread将log buffer中的数据写入文件、并通知文件系统同步文件。这个设置是最安全的,能够保证不论是MySQL Crash、OS Crash还是主机断电都不会丢失任何已经提交的数据。innodb_flush_log_at_trx_commit = 2,当设置为2的时候,Log Thread会在每次事务结束的时候将数据写入事务日志,仅仅是调用了文件系统的文件写入操作。而文件系统都是有缓存机制的,所以Log Thread的写入并不能保证内容已经写入到物理磁盘完成持久化的动作。文件系统什么时候会将缓存中的数据同步到物理磁盘、文件,Log Thread就完全不知道了。所以,当设置为2的时候,MySQL Crash并不会造成数据的丢失,但是OS Crash或主机断电后可能丢失的数据量就完全控制在文件系统上了

Innodb数据存储优化

  • 减小 secondary index 的大小,提高访问效率,作为主键的字段所占用的存储空间越 小越好,最好是 INTEGER 类型。当然这并不是绝对的,字符串类型的数据同样也可以作为 Innodb 表 的主键
  • 创建表的时候尽量自己指定相应的主键,让数据按照自己预设的顺序排序存放,一提高特定条 件下的访问效率
  • 尽可能不要在主键上面进行更新操作,减少因为主键值的变化带来数据的移动。
  • 尽可能提供主键条件进行查询

分散 IO 提升磁盘响应

  • 建议将数据文件和事务日志文件分别存放 于不同的物理磁盘上面以降低磁盘的相互争用,提高整体 IO 性能

其他优化

  • Innodb_flush_method控制着innodb数据文件及redo log的打开
  • 刷写模式:fdatasync(默认),O_DSYNC,O_DIRECT
  • 默认是fdatasync,调用fsync()去刷数据文件与redo log的buffer
  • O_DSYNC时,innodb会使用O_SYNC方式打开和刷写redo log,使用fsync()刷写数据文件
  • O_DIRECT时,innodb使用O_DIRECT打开数据文件,使用fsync()刷写数据文件跟redo log
  • innodb_thread_concurrency
  • Autocommit



InnoDB如何保持数据的一致性呢?MVCC了解下?

InnoDB是一个 多版本存储引擎:它保留有关已更改行的旧版本的信息,以支持诸如并发和回滚之类的事务功能 。该信息以称为回滚段的数据结构存储在表空间中 (在Oracle中类似的数据结构之后)。InnoDB 使用回滚段中的信息来执行事务回滚中所需的撤消操作。它还使用该信息来构建行的早期版本,以实现 一致的读取。

在内部,InnoDB向数据库中存储的每一行添加三个字段。6个字节的DB_TRX_ID字段表示插入或更新该行的最后一个事务的事务标识符。此外,删除在内部被视为更新,在该更新中,行中的特殊位被设置为将其标记为已删除。每行还包含一个7字节的 DB_ROLL_PTR字段,称为滚动指针。回滚指针指向写入回滚段的撤消日志记录。如果行已更新,则撤消日志记录将包含在更新行之前重建行内容所必需的信息。一个6字节的DB_ROW_ID字段包含一个行ID,该行ID随着插入新行而单调增加。如果 InnoDB自动生成聚集索引,该索引包含行ID值。否则,该 DB_ROW_ID列不会出现在任何索引中。

回滚段中的撤消日志分为插入和更新撤消日志。插入撤消日志仅在事务回滚时才需要,并且在事务提交后可以立即将其丢弃。更新撤消日志也用于一致的读取中,但是只有在不存在为其InnoDB分配了快照的事务( 一致的读取可能需要更新撤消日志中的信息来构建数据库的早期版本)后,才可以将其删除行。

定期提交您的事务,包括仅发出一致读取的事务。否则, InnoDB无法丢弃更新撤消日志中的数据,并且回滚段可能会变得太大,从而填满了您的表空间。

回滚段中撤消日志记录的物理大小通常小于相应的插入或更新的行。您可以使用此信息来计算回滚段所需的空间。

在InnoDB多版本方案中,当您使用SQL语句删除行时,并不会立即将其从数据库中物理删除。InnoDB仅在丢弃为删除而编写的更新撤消日志记录时,才物理删除相应的行及其索引记录。此删除操作称为purge,它非常快,通常花费与执行删除操作的SQL语句相同的时间顺序。

如果您以大约相同的速率在表中以较小的批次插入和删除行,则由于所有“ 死 ”行,清除线程可能会开始滞后并且表可能会变得越来越大 ,从而使所有内容都受磁盘约束慢。在这种情况下,请限制新行的操作,并通过调整innodb_max_purge_lag系统变量来向清除线程分配更多资源


mysql 为什么会存在间隙锁,是来解决什么问题的呢,有什么缺陷吗

虽然Innodb的锁定机制和Oracle有不少相近的地方,但是两者的实现确是截然不同的。总的来说就是 Oracle 锁定数据是通过需要锁定的某行记录所在的物理 block 上的事务槽上表级锁定信息,而 Innodb的锁定则是通过在指向数据记录的第一个索引键之前和最后一个索引键之后的空域空间上标记锁定信息而实现的。Innodb 的这种锁定实现方式被称为“NEXT-KEY locking”(间隙锁),因为 Query 执行过程中通过过范围查找的华,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。


间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。而 Innodb 给出的解释是为了组织幻读的出现,所以他们选择的间隙锁来实现锁定。


除了间隙锁给 Innodb 带来性能的负面影响之外,通过索引实现锁定的方式还存在其他几个较大的性能隐患:
● 当 Query 无法利用索引的时候,Innodb 会放弃使用行级别锁定而改用表级别的锁定,造成并发性能的降低;
● 当 Quuery 使用的索引并不包含所有过滤条件的时候,数据检索使用到的索引键所只想的数据可能有部分并不属于该 Query 的结果集的行列,但是也会被锁定,因为间隙锁锁定的是一个范围,而不是具体的索引键;
● 当 Query 在使用索引定位数据的时候,如果使用的索引键一样但访问的数据行不同的时候(索引只是过滤条件的一部分),一样会被锁定

扩展

mysql是如何 死锁检测、事务大小判断的呢 ?你知道吗

行级锁定肯定会带来死锁问题,Innodb 也不可能例外。至于死锁
的产生过程我们就不在这里详细描述了,在后面的锁定示例中会通过一个实际的例子为大家爱展示死锁的产生过程。这里我们主要介绍一下,在 Innodb 中当系检测到死锁产生之后是如何来处理的。在 Innodb 的事务管理和锁定机制中,有专门检测死锁的机制,会在系统中产生死锁之后的很短时间内就检测到该死锁的存在。当 Innodb 检测到系统中产生了死锁之后,Innodb 会通过相应的判断来选这产生死锁的两个事务中较小的事务来回滚,而让另外一个较大的事务成功完成。那 Innodb 是以什么来为标准判定事务的大小的呢?MySQL 官方手册中也提到了这个问题,实际上在 Innodb 发现死锁之后,会计算出两个事务各自插入、更新或者删除的数据量来判定两个事务的大小。也就是说哪个事务所改变的记录条数越多,在死锁中就越不会被回滚掉。但是有一点需要注意的就是,当产生死锁的场景中涉及到不止Innodb 存储引擎的时候,Innodb 是没办法检测到该死锁的,这时候就只能通过锁定超时限制来解决该死锁了。

mysql 有关架构该怎么优化。整理中。。。敬请关注

你可能感兴趣的:(mysql,数据库优化)