天天看点

mysql 原理及配置优化

假设我们用文本存储的数据和数据库里一样的数据结构并且遵循三范式,那数据库相比文本存储有什么大的优势呢。

有了这个疑问后我们来简单探究下mysql数据库的原理,简单了解原理后我们在学习下配置的简单优化。

我们先看下mysql的结构图

mysql 原理及配置优化

1.最上层是一些客户端和连接服务,包含本地sock通信和大多数基于客户端/服务端工具实现的类似于tcp/ip的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。

2.第二层架构主要完成大多少的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化及部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如过程、函数等。在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化如确定查询表的顺序,是否利用索引等,最后生成相应的执行操作。如果是select语句,服务器还会查询内部的缓存。如果缓存空间足够大,这样在解决大量读操作的环境中能够很好的提升系统的性能。

3.存储引擎层,存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过API与存储引擎进行通信。不同的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取。

如果你看着很复杂的话,我们再来个简单点的图。如果你看上面的描述理解了一些在看下面的图,你可能更好理解些。

mysql 原理及配置优化

这上面的三层就相比文本存储的大概三个优点,其实还有最重要的,那就是事物和锁,涉及并发。

比如: 当数据库中有多个操作需要修改同一数据时,不可避免的会产生数据的脏读。这时就需要数据库具有良好的并发控制能力,这一切在MySQL中都是由服务器和存储引擎来实现的。

解决并发问题最有效的方案是引入了锁的机制,锁在功能上分为共享锁(shared lock)和排它锁(exclusive lock)即通常说的读锁和写锁。当一个select语句在执行时可以施加读锁,这样就可以允许其它的select操作进行,因为在这个过程中数据信息是不会被改变的这样就能够提高数据库的运行效率。当需要对数据更新时,就需要施加写锁了,不在允许其它的操作进行,以免产生数据的脏读和幻读。

注意: 数据库里会出现一种死锁的情况,就是我占着读锁,然而写锁要我读锁里的资源去写入东西,但是我读锁要读出写锁占着的资源,这样就互相占着对方的资源而不放形成死锁了。InnoDB引擎解决死锁的方案是将持有最少排它锁的事务进行回滚。

锁有粒度大小,有表级锁(table lock)和行级锁(row lock),分别在数据操作的过程中完成行的锁定和表的锁定。

表锁是MySQL中基本的锁策略,并且是开销最小的策略。当用户在对一张表进行写操作之前,首先获得写锁,于是,它阻塞了其他链接的读取和写入操作,只有写锁接触的时候,其他链接才能获得读锁。

不仅如此,MySQL还设置了锁的优先级,在操作列队中MySQL可能会把写入操作插入到读取操作之前。

行级锁可以最大程度的支持并发处理(同时也带来了最大的锁开销)。行级锁只在存储引擎中实现。行级锁比表锁更加精确,他把锁的对象精确到了对象的某一行,但也就意味着需要创建更多的锁。

注:理论上锁定的资源越小,锁定范围越精确,那么并发性能就会越高。但是事实上,创建一个数据锁也会造成系统的开销,如果系统通过大量的时间来管理锁,而不是存取数据,系统的性能反而会降低。

事务

事务其实就是一个独立的工作单元。如果数据库引擎能够完成事务中的每一项操作,那么全组的SQL语句都会被执行,如果任何一条语句因为崩溃或者其他原因无法执行,那么所有语句都不执行。并且回滚到快照。

MySQL大多数事务型的存储引擎都不是简单的行级锁,基于性能的考虑,他们一般都同时实现了多版本并发控制(MVCC)(这个版本控制有点像SVN那样,和hibernate中的乐观锁差不多机制)。它是通过保存数据中某个时间点的快照来实现的,这样就保证了每个事务看到的数据都是一致的。

mysql 的配置优化。

从MySQL 5.5版本开始,InnoDB就是默认的存储引擎并且它比任何其他存储引擎的使用都要多得多。

innodb_buffer_pool_size

缓冲池是数据和索引缓存的地方:这个值越大越好,这能保证你在大多数的读取操作时使用的是内存而不是硬盘。一般设置为物理内存的80%

max_connections

MySQL的最大连接数,增加该值增加mysqld 要求的文件描述符的数量。如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySQL会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。

show variables like ‘max_connections’ 最大连接数

show status like ‘max_used_connections’响应的连接数

max_used_connections / max_connections * 100% (理想值≈ 85%)

query_cache_size

使用查询缓冲,MySQL将查询结果存放在缓冲区中,今后对于同样的SELECT语句(区分大小写),将直接从缓冲区中读取结果。

通过检查状态值Qcache_*,可以知道query_cache_size设置是否合理(上述状态值可以使用SHOW STATUS LIKE ‘Qcache%’获得)。

query_cache_type指定是否使用查询缓冲,可以设置为0、1、2,该变量是SESSION级的变量。

query_cache_type设为1即可。在设 置了这个属性后,MySQL在执行任何SELECT语句之前,都会在它的缓冲区中查询是否在相同的SELECT语句被执行过,如果有,并且执行结果没有过 期,那么就直接取查询结果返回给客户端。但在写SQL语句时注意,MySQL的查询缓冲是区分大小写的,大小写不一样它会重新去数据库查。

虽然不设置查询缓冲,有时可能带来性能上的损失,但有一些SQL语句需要实时地查询数据,或者并不经常使用(可能一天就执行一两次)。这样就需要把 缓冲关了。当然,这可以通过设置query_cache_type的值来关闭查询缓冲,但这就将查询缓冲永久地关闭了。

在MySQL 5.0中提供了一种可以临时关闭查询缓冲的方法:

(1) SELECT SQL_NO_CACHE field1, field2 FROM TABLE1

以上的SQL语句由于使用了SQL_NO_CACHE,因此,不管这条SQL语句是否被执行过,服务器都不会在缓冲区中查找,每次都会执行它。

我们还可以将my.ini中的query_cache_type设成2,这样只有在使用了SQL_CACHE后,才使用查询缓冲。

(2) SELECT SQL_CALHE * FROM TABLE1

mysql> show global status like ‘qcache%‘;

mysql> show variables like ‘query_cache%‘;

查询缓存利用率= (query_cache_size – Qcache_free_memory) / query_cache_size * 100%

查询缓存利用率在25%以下的话说明query_cache_size设置的过大,可适当减小;查询缓存利用率在80%以上而且Qcache_lowmem_prunes > 50的话说明query_cache_size可能有点小,要不就是碎片太多。

查询缓存命中率= (Qcache_hits – Qcache_inserts) / Qcache_hits * 100%

命中率很差的话,可能写操作比较频繁吧

show status like ‘Slow_queries’//慢查询的次数 (默认是10秒中就当做是慢查询,如下图所示)

  查询mysql的慢查询时间

    Show variables like ‘long_query_time’;

  修改mysql 慢查询时间

    set long_query_time=2//如果查询时间超过2秒就算作是慢查询

mysql支持把慢查询语句记录到日志文件中。程序员需要修改my.ini的配置文件,默认情况下,慢查询记录是不开启的。

  开启慢查询记录的步骤:

  打开 my.ini ,找到 [mysqld] 在其下面添加

  long_query_time = 2

  

  log-slow-queries = D:/mysql/logs/slow.log #设置把日志写在那里,可以为空,系统会给一个缺省的文件。

  我们可以从日志中看出哪些查询语句查询超过了,你设定的时间。

  然后可以分析你的查询语句。主要是用explain分析查询。

使用 EXPLAIN 关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。这可以帮你分析你的查询语句或是表结构的性能瓶颈。

线程缓存

线程缓存保存了和当前连接无关的线程,这些线程可以供新连接使用。当要求一个新的连接时,如果线程缓存中的连接能够被使用时,新的连接就不会被创建,而使用线程缓存中的连接。当连接关闭时,又会将该线程放回到线程缓存中(前提是线程缓存中有可用的空间)。

参数thread_cache_size用于控制线程缓存的大小,默认值为0,表示没有线程缓存,这个参数为动态参数可以随时更改,如下:

mysql> show variables like ‘thread_cache_size’;

+——————-+——-+

| Variable_name | Value |

+——————-+——-+

| thread_cache_size | 0 |

+——————-+——-+

通过 Threads_cached 和 Threads_created 状态变量来监控已缓存的线程数和已创建的线程数。当系统有大量的连接时,根据Threads_created或Threads_connected状态变量的值来适当调整线程缓存的大小,以减少线程创建的开销。

MySQL线程缓存原理与连接池原理相似。

innodb_log_buffer_size: 这项配置决定了为尚未执行的事务分配的缓存。

其实还有很多配置文件里的其他属性,但是我们要学会用 show 去定位和查看影响我们数据的到底是什么原因,并且每次改的话最好只改一个配置项,这样才能知道我们改的影响有多大。