您的位置:首页 > 数据库 > MySQL

Mysql book notes

2016-08-01 00:16 288 查看

并发控制

读写锁:共享锁(shared lock)和排他锁(exclusive lock),也叫读锁(read lock)或写锁(write lock)

锁粒度:表锁(table lock)(开销最小的锁策略)和行级锁(row lock)(最大程度的支持并发处理,同时带来了最大的锁开销)

事务

ACID(原子,一致,隔离,持久)

四种隔离级别:

READ UNCOMMITED(未提交读)(导致脏读 Dirty Read)

READ COMMITED(提交读)(又叫不可重复读 nonrepeatable read)(大多数数据库默认隔离级别,mysql不是)

REPEATETABLE READ(可重复读)(解决了脏读,但无法解决幻读 Phantom Read)(Mysql的默认事务隔离级别)

SERIALIZABLE(可串行化)(最高的隔离级别)

REPEATETABLE READ(mysql),解决了脏读的问题,但还是有幻读的可能。

脏读指的是旧的记录在同一事务多次读取结果一致

幻读是指某一范围内被其他事务添加新记录。

死锁:数据库系统实现各种死锁检测和死锁超时机制。InnoDB目前处理死锁的方法:将持有最少行级排他锁的事务进行回滚。

死锁发生以后,只有部分或者完全回滚其中一个事务,才能打破死锁。

事务日志:先写事务日志,再持久话数据本身到磁盘。提交事务效率,而且万一系统刚好奔溃可以通过日志恢复数据。预写式日志(Write-AHead Logging),修改数据需要写两次磁盘。

存储引擎

Mysql提供两种事务型的存储引擎:InnoDB和NDB Cluster。

Mysql默认采用自动提交(AUTOCOMMIT)模式。

MyISAM不支持事务。所以在事务中混用存储引擎,非事务型的存储引擎的表数据不能回滚。

DDL语句会导致当前事务提交。

Mysql可以设置隔离级别,在下一个事务开始时生效。

MVCC多版本并发控制(可以认为是行级锁的一个变种)

InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。

MVCC只在REPEATETABLE READ和READ COMMITED两个隔离级别下工作。

Mysql 存储引擎,默认是InnoDB。

InnoDB采用MVCC来支持并发,并且实现了四个标准的隔离级别。其默认级别是REPEATABLE READ,并且通过间隙锁(next-key locking)策略防止幻读的出现。间隙锁使得InnoDB不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定,以防止幻影行的插入。

InnoDB基于聚簇索引建立的。聚簇索引对主键查询有很高的性能。不过它的二级索引(secondard index 非主键索引)中必须包含主键列,所以如果主键列很大的话,其他的所有索引都会很大。因此,若表的索引较多的话,主键应当尽量小。

Mysql5.1及之前默认的存储引擎是MyISAM。MyISAM不支持事务和行级锁。

MyISAM的存储:MyISAM会将表存储在两个文件中:数据文件和索引文件,分别以.MYD和.MYI为扩展名。

MyISAM对整张表加锁,而不是针对行。

Mysql拥有分层的架构。上层是服务器层的服务和查询执行引擎,下层则是存储引擎。

Mysql 基准测试

吞吐量throughout,响应时间或者延迟latency,并发性,可扩展性

abTest Apache

jMeter

服务器性能剖析

show profiles


show profiles for query 1


show status


explain


show global status


Schema与数据类型优化

尽量避免NULL(可为NULL的列会使用更多的存储空间,当可谓NULL的列被索引时,每个索引需要一个额外的字节。。)

通常把可为NULL的列改为NOT NULL带来的性能提升比较小。

存储MD5等定长的字符串,使用CHAR

如果存储UUID值,应该移除”-“符号;或者更好的做法是,用UNHEX()函数转换UUID值为16字节的数字,并且存储在一个BINARY(16)列中。检索时可以通过HEX()函数来格式化为十六进制格式。

IPv4地址应该使用23位无符号整数存储,而不是varchar(15)。Mysql提供INET_ATON()和INET_NTOA()函数在这两种表示方法之间转换。

范式化的schema每个事实数据会出现并且只出现一次,缺点是通常需要关联。反范式化的schema因为所有数据都在一张表中,可以很好地避免关联。

事实上,实际工作中,完全范式化或者反范式化的schema是不存在的。

最常见的反范式式化数据的方法是复制或者缓存,在不同的表中存储相同的特定列。

MySql中的varchar类型:http://www.cnblogs.com/doit8791/archive/2012/05/28/2522556.html

索引

索引类型

B-Tree 索引:适用于全键值,键值范围,或键前缀查找。其中键前缀查找只适用于根据最左前缀的查找。

全值匹配(索引的所有列都使用到),匹配最左前缀(只使用索引第一列),匹配列前缀(只使用索引第一列的前缀),匹配范围值(只使用索引第一列),精确匹配某一列并范围匹配另一列(第一至n列全匹配,接着第n+1列模糊匹配),只访问索引的查询(即无需访问数据行,”索引覆盖” 优化)

B-Tree索引限制:

如果不是按照索引的最左列开始查找,则无法使用索引。

不能跳过索引中的列。

如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找。

哈希索引 (memory引擎)

空间数据索引(R-tree)(MyISAM支持)

全文索引(特殊类型的索引,它查找的是文本中的关键词,而不是直接比较索引中的值)

在相同列上同时创建全文索引和基于值的B-Tree索引不会有冲突,全文索引适用于MATCH AGAINST操作,而不是普通的WHERE条件操作。

对于非常小的表,大部分情况下简单的全表扫描更高效。对于中到大型的表,索引非常有效。但对于特大型的表,可以使用分区技术等。

高性能的索引策略

独立的列(如WHERE article_id + 1 =5 不能匹配到索引),是指索引列不能是表达式的一部分,也不能是函数的参数。

前缀索引和索引选择性(LEFT(city,4) AS pref)

多列索引

如果在EXPLAIN中看到有索引合并,应该好好检查一下查询和表的结构,看是不是已经是最优的。

选择合适的索引列顺序

将选择性最高的列放在索引最前列(当不需要考虑排序和分组时)

选择性最高,指定条件之后返回的列少!!!

聚簇索引

不是一种单独的索引类型,而是一种数据存储方式。

InnoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行。

当表有聚簇索引时,它的数据行实际上存放在索引的叶子页中。术语“聚簇”表示数据行和相邻的键值紧凑地存储在一起。因为无法同时把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。

InnDB将通过主键聚集数据,也就是被索引的列就是主键列。

如果没有定义主键,InnDB会选择一个唯一的非空索引代替。如果没有这样的索引,InnDB会隐式定义一个主键来作为聚簇索引。

聚簇索引将索引和数据保存在同一个B-Tree中,因此从聚簇索引中获取数据通常比非聚簇索引中查找要快。

使用覆盖索引扫描的查询可以直接使用页节点中的主键值???

二级索引(非聚簇索引)可能比想象中大,因为在二级索引的叶子节点包含了引用行的主键列

二级索引访问需要两次索引查找,而不是一次。(二级索引叶子节点保存的不是指向行的物理位置的指针,而是行的主键值)

(即两次B-Tree查找,对于InnoDB,自适应哈希索引能够减少这样的重复工作)

在InnoDB中,聚簇索引“就是”表,所以不像MyISAM那样需要独立的行存储。

如果正在使用InnDB表并且没有什么数据需要聚集,那么可以定义一个代理键(surrogate key)作为主键,这种主键的数据应该和应用无关。最简单的方法是使用AUTO_INCREMENT自增列。这样可以保证数据行是按顺序写入,对于数据主键做关联操作的性能也会更好。

最好避免使用随机的(不连续且值的分布范围非常大)聚簇索引,特别是对于I/O密集型的应用。从性能的角度考虑,使用UUID作为聚簇索引会很槽糕,它使得聚簇索引的插入变得完全随机(而不是简单的从后面直接插入)。也许需要做一次OPTIMIZE TABLE来重建表并优化页的填充。

顺序的主键不好的情景:高并发的工作负载,主键的上界成为“热点

”,并发插入可能导致间隙锁竞争。

覆盖索引

如果一个索引包含(或者覆盖)所有需要查询字段的值,就称之为“覆盖索引”(不需要会表查询)。

select * 或者select的字段不在索引的范围内,则无法用到覆盖索引,可以使用延迟关联(deferred join)的方式在查询的一部分中使用覆盖索引。

使用索引扫描来做排序

MySQL有两种方式可以生成有序的结果:通过排序操作;或者按索引顺序扫描。如果EXPLAIN出来的type列的值为“index”,则说明MySQL使用了索引扫描来做排序。

扫描索引本身很快,因为只需要从一条索引记录移动到紧接着的下一条记录。

只有当索引的列顺序和ORDER BY子句的顺序完全一致,并且所有列的排序方向(倒序或正序)都一样时,MySQL才能够使用索引来对结果做排序。

如果查询需要关联多张表,则只有当ORDER BY子句引用的字段全部为第一张表时,才能使用索引做排序。

使用索引做排序的一个重要的用法是当查询同时有ORDER BY和LIMIT的时候??

压缩(前缀压缩)索引

MyISAM

冗余和重复索引

重复索引是指在相同的列上按照相同的顺序创建相同类型的索引,应该避免这样创建重复索引,发现以后也应该立即移除。

冗余索引:如果创建了索引(A,B),再创建索引(A)就是冗余索引,因为这只是前一个索引的前缀索引。但创建索引(B,A),则不是冗余索引。索引(B)也不是,因为B不是索引(A,B)的最左前缀列。

冗余索引通常发生在为表添加新索引的时候。例如可能会增加一个新的索引(A,B),而不是扩展已有的索引(A)。

还有一种情况是将一个索引扩展为(A,ID),其中ID是主键,对于InnoDB来说主键列已经包含在二级索引中了。

大多数情况下都不需要冗余索引,应该尽量扩展已有的索引。但有时处于性能方面的考虑需要冗余索引,因为扩展已有的索引会导致其变化太大,从而影响其他使用该索引的查询的性能。

有时如果想让两个查询都变得很快,就需要两个索引,尽管这样一来原来的单列索引是冗余的了。

未使用的索引

删除

索引和锁

InnoDB在二级索引使用共享(读)锁,在访问主键索引需要排他(写)锁。

??

尽可能将需要做范围查询的列放在索引的后面,以便优化器能使用尽可能多的索引列。

对于范围查询,MySQL无法使用范围后面的其他索引列了,但是对于“多个等值条件查询”则没有这个限制(in 语句)。

多个简单查询程序处理,代替复杂查询

查询性能优化

这一章看得相当粗略。。。

以下情况不会被缓存

查询中包含任何用户自定义函数、存储函数、用户变量

优化:常量替代

子查询、临时表

优化:采用联接方式避免子查询;

系统表、或者任何包含列级别权限的表

慢查询基础:优化数据访问

查询性能低下最基本的原因是访问的数据太多。某些查询可能不可避免的需要筛选大量数据。

1. 确认应用程序是否在检索大量超过需要的数据。这通常意味着访问了太多的行,但有时候也可能是访问太多的列。

2. 确认MySQL服务器是否在分析大量 超过需求的数据行。

MySQL是否在扫描额外的记录

衡量查询开销的三个指标

1. 响应时间

响应时间只是个表面上的值(服务时间+排队时间)。

2. 扫描的行数

3. 返回的行数

理想情况下扫描的行数和返回的行数是相同的。

MySQL不会告诉我们生成结果实际上需要扫描多少行数据,而只会告诉我们生成结果时一共扫描了多少行数据。

查询执行的基础



MySQL客户端/服务器通信协议

“半双工”

MySQL将结果集返回客户端是一个增量、逐步返回的过程。

结果集的每一行都会以一个满足MySQL客户端/服务器通信协议的封包发送,再通过TCP协议进行传输(可能批量传输)。

查询优化器



查询排序

当不能使用索引生成排序结果的时候,MySQL需要自己进行排序,如果数据量小则在内存中进行,如果数据量大则需要使用磁盘,不过MySQL将这一过程统一称为文件排序(filesort)。

优化LIMIT分页





MySQL EXPLAIN

http://www.cnblogs.com/xuanzhi201111/p/4175635.html

Extra

该列包含MySQL解决查询的详细信息,有以下几种情况:

Using where:列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤

Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询

Using filesort:MySQL中无法利用索引完成的排序操作称为“文件排序”

Using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。

Impossible where:这个值强调了where语句会导致没有符合条件的行。

Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行


type :找到所需行的方式

ALL: 扫描全表、index: 扫描全部索引树、range: 索引范围扫描、ref: 非唯一性索引扫描、eq_ref:唯一性索引扫描、const:常量扫描,比如主键。

一般来说:
rows
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: