[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dI3iL3TR-1588946884165)(media/15889432895273/15889440607388.jpg)]
默认一直有的排序算法。取出满足过滤条件的用于排序条件的字段以及可以直接定位到行数据的行指针信息,在 Sort Buffer 中进行实际的排序操作,然后利用排好序之后的数据根据行指针信息返回表中取得客户端请 求的其他字段的数据,再返回给客户端
MySQL4.1 版本才开始增加的改进版排序算法。根据过滤条件一次取出排序字段以及客户端请求的所有其他字段的数据,并将不需要排序的字 段存放在一块内存区域中,然后在 Sort Buffer 中将排序字段和行指针信息进行排序,最后再利用 排序后的行指针与存放在内存区域中和其他字段一起的行指针信息进行匹配合并结果集,再按照顺 序返回给客户端
扩展的两种算法优先使用哪种呢,是通过max_length_for_sort_data参数控制
####当我们无法避免排序操作的时候,我们又该如何来优化呢?
主要在于他需要在扫描索引的时候,读取所有 满足条件的索引键,然后再根据读取恶的数据来完成 GROUP BY 操作得到相应结果
第一范式:要求有主键,并且要求每一个字段原子性不可再分
第二范式:要求所有非主键字段完全依赖主键,不能产生部分依赖
第三范式:所有非主键字段和主键字段之间不能产生传递依赖
对于基于性能的数据库Schema设计,我们并不能完全以规范化范式理论来作为唯一的指导。在设计过程中,应该从实际需求出发,以性能提升为根本目标来展开设计工作,很多时候为了尽可能提高性能,我们必须做反范式设计
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。值越小,被降级的可能性越大
选择合适的事务隔离级别
事务与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是一个 多版本存储引擎:它保留有关已更改行的旧版本的信息,以支持诸如并发和回滚之类的事务功能 。该信息以称为回滚段的数据结构存储在表空间中 (在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系统变量来向清除线程分配更多资源
虽然Innodb的锁定机制和Oracle有不少相近的地方,但是两者的实现确是截然不同的。总的来说就是 Oracle 锁定数据是通过需要锁定的某行记录所在的物理 block 上的事务槽上表级锁定信息,而 Innodb的锁定则是通过在指向数据记录的第一个索引键之前和最后一个索引键之后的空域空间上标记锁定信息而实现的。Innodb 的这种锁定实现方式被称为“NEXT-KEY locking”(间隙锁),因为 Query 执行过程中通过过范围查找的华,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。
间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。而 Innodb 给出的解释是为了组织幻读的出现,所以他们选择的间隙锁来实现锁定。
除了间隙锁给 Innodb 带来性能的负面影响之外,通过索引实现锁定的方式还存在其他几个较大的性能隐患:
● 当 Query 无法利用索引的时候,Innodb 会放弃使用行级别锁定而改用表级别的锁定,造成并发性能的降低;
● 当 Quuery 使用的索引并不包含所有过滤条件的时候,数据检索使用到的索引键所只想的数据可能有部分并不属于该 Query 的结果集的行列,但是也会被锁定,因为间隙锁锁定的是一个范围,而不是具体的索引键;
● 当 Query 在使用索引定位数据的时候,如果使用的索引键一样但访问的数据行不同的时候(索引只是过滤条件的一部分),一样会被锁定
行级锁定肯定会带来死锁问题,Innodb 也不可能例外。至于死锁
的产生过程我们就不在这里详细描述了,在后面的锁定示例中会通过一个实际的例子为大家爱展示死锁的产生过程。这里我们主要介绍一下,在 Innodb 中当系检测到死锁产生之后是如何来处理的。在 Innodb 的事务管理和锁定机制中,有专门检测死锁的机制,会在系统中产生死锁之后的很短时间内就检测到该死锁的存在。当 Innodb 检测到系统中产生了死锁之后,Innodb 会通过相应的判断来选这产生死锁的两个事务中较小的事务来回滚,而让另外一个较大的事务成功完成。那 Innodb 是以什么来为标准判定事务的大小的呢?MySQL 官方手册中也提到了这个问题,实际上在 Innodb 发现死锁之后,会计算出两个事务各自插入、更新或者删除的数据量来判定两个事务的大小。也就是说哪个事务所改变的记录条数越多,在死锁中就越不会被回滚掉。但是有一点需要注意的就是,当产生死锁的场景中涉及到不止Innodb 存储引擎的时候,Innodb 是没办法检测到该死锁的,这时候就只能通过锁定超时限制来解决该死锁了。