MySql性能调优(一)

版权声明:原创文章,转载请注明出处,来自https://blog.csdn.net/Jacabe https://blog.csdn.net/Jacabe/article/details/82810658

一。Mysql内部整个结构和执行流程

MySQL简易模块图:

简易图:1.连接/线程处理:主要负责连接和线程处理、授权认证、安全。

                                           当客户端连接到mysql服务器时,服务器需要对其进行认证,认证基于用户名,原始主机信息和密                                                   码。

2.查询缓存/解析器:功能有解析,分析,优化,缓存,内置函数。

                                 mysql解析查询并创建内部数据结构(解析树),然后对其优化,包括重写查询、决定表的读取顺序,以及选                                    择合适的索引。优化器会请求存储引起提供容量或某个具体的开销信息,以及表数据的统计信息等。

3.存储引擎:负责Mysql中数据存储和提取。

数据库范式

    第一范式:字段列不可分,如:【联系人】(姓名,性别,电话),一个联系人有家庭电话和公司电话,不符合 1NF;

   第二范式:有主键,非主键字段完全依赖主键。如:订单明细表【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName),Discount(折扣),Quantity(数量)完全依赖(取决)于主键(OderID,ProductID),而 UnitPrice,ProductName 只依赖于 ProductID,不符合2NF;

  第三范式:非主键字段不能相互依赖(如:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况),

              每列都与主键有直接关系,不存在传递依赖。如:订单表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主键是(OrderID),CustomerName,CustomerAddr,CustomerCity 直接依赖的是 CustomerID(非主键列),而不是直接依赖于主键,它是通过传递才依赖于主键,所以不符合 3NF。

1)锁

    处理并发读或写时,可以通过实现一个由两种类型的锁组成的锁系统拉埃解决。

    也就是共享锁(shared lock)和排他锁(exclusive lock),也叫读锁 和写锁。

    读锁 :是共享的,多个客户端在同一时刻可以同时读取同一个资源,互不干扰。

    写锁:是排他的只有一个用户(客户端)能执行写入,并防止其他用户读取正在写入的同一资源。

    尽量只锁定修改的部分数据,而不是所有资源,来提供共享资源的

Mysql各存储引起使用了三种类型(级别)的锁定机制:行级锁定,页级锁定和表级锁定

表锁:与行锁相反,最大颗粒度锁定机制,实现逻辑简单,系统开销负面影响小,获取锁和释放锁速度快,会锁定整张表,一个用            户在对表进行写操作(插入、删除、更新等)前,需要先获得写锁,会阻塞其他用户对该表读写操作。 读锁之间是不                        相互阻塞的。

            ---------》主要使用该锁的是: MyISAM,Memory,CSV等一些非事务性存储引擎,

 行锁:    最大特点,锁定对象颗粒度很小,每次获取锁和释放锁需要做很多事情,所以开销消耗比较大,行锁页最容易发生死                     锁,在InnoDB和XtraDB,以及其他的一些存储 引擎中实现了行级锁。

               --------》主要使用该锁的是:Innodb存储引擎和NDB存储引擎,

               ------>InnoDB的行锁是基于索引的,也就是如果那个表那一行没有索引,行锁是无效的。

  页锁:特点是锁定颗粒度介于行级锁定与表级锁定之间,会发生死锁,并发处理能力也介于两者之间。

              ----------》主要使用该锁的是:BerkeleyDB存储引擎的锁定方式。

InnoDB的锁定机制和Oracle有很多相似之处,InnoDB的行级锁定分为两种类型,共享锁和排他锁。

InnoDB:使用意向锁(表级锁定)的概念,分为了意向共享锁和意向排他锁。

 意向锁的作用就是当一个事务在需要获取资源锁定的时候,如果遇到自己需要的资源已经被排他锁占用的时候,该事务可以需要锁定行的表上面添加一个合适的意向锁。如果需要一个共享锁,那么就在表上添加一个意向共享锁。如果某行添加了排他锁,那么就在表上添加一个意向排他锁。意向共享锁可以有多个,意向排他锁只能有一个。

InnoDB锁定模式分为:共享锁,排他锁,意向共享锁,意向排他锁。

Oracle锁定是通过需要锁定的某行记录所在的物理block上的事务槽上表级锁定信息。

Innodb锁定是通过在指向数据记录的第一个索引键之前和最后一个索引键之后的空域空间上标记锁定信息而实现的。这种锁定实现方式称为:"NEXT-KEY locking"(间隙锁)。(如果是通过范围查询数据的话,会锁定整个范围的所有的索引键值)

间隙锁的致命弱点:当锁定一个范围键值之后,即使不存在也会被锁定,而造成在锁定的时候无法插入锁定范围内的任何数据。

                              在某些场景下有危害,而Innodb给出的解释是为了阻止出现幻读,所以选择间隙锁。

通过索引实现锁定的方式(行锁)存在的隐患:

        1、当Query无法利用索引的时候,Innodb会放弃行锁而改用表级锁定,造成并发性能降低。

         2、当Query使用索引不包括所有过滤条件的时候,数据检索使用到的索引键所获取的数据可能有不属于该Query的结果集的行列,但是也会被锁定

         3、当Query使用索引,定位数据的时候,如果使用的索引键一样,但访问数据行不同,数据都会被锁定。

死锁:如果两个事务都执行了第一条update语句,更新了一行数据,同时也锁定了该行数据,接着每个事务都尝试去执行第二条update语句,却发现该行已被对方锁定,然后两个事务都等待对方释放锁,同时又持有对方需要的锁,则陷入死循环,死锁。

         为了解决死锁,数据库系统实现了各种死锁检测和死锁超时机制。如:InnoDB存储引擎,检测到死锁的循环依赖,并立即返回一个错误。InnoDB目前处理死锁的方法时,将持有最少行级排他锁的事务进行回滚。

           InnoDB检测到系统中产生死锁后,InnoDB会通过相应的判断来选择较小事务的进行回滚。而让较大事务的成功顺利执行。mysql官方手册中提到:InnoDB发现死锁后,会计算出两个事务各自插入、更新或者删除的数据量来判断两个事务的大小,也就是那个事务锁改变的记录条数越多,在死锁中就不会被回滚。当死锁涉及不止存储引擎,InnoDB就没办法检测到死锁了。

            对于非常容易产生死锁的业务部分,可以尝试通过表级锁定来减少死锁的产生概率。

  MyISAM表锁优化:

                      1、缩短锁定时间;  减少复杂的Query(查询),复杂的Query(查询)分拆成几个小的查询

                                                        建立高效的索引,控制字段类型,优化MyISAM文件

                        2、并行操作:并发插入(Concurrent Insert)功能参数concurrent_insert

                         3、合理利用读写优先级。

Innodb行锁优化:

            1、尽可能让所有数据检索都通过索引完成,避免Innodb因为无法通过索引键枷锁而升级为表级锁定,

            2、合理设计索引

            3、减少基于范围的数据检索过滤条件。

             4、控制事务大小,减少锁定的资源量

InnoDB 显示锁定  -->

       SELECT ...LOCK IN SHARE MODE

         SELECT ...FOR UPDATE

       这两个语句不属于 范式。

2)事务

事务:事务就是一组原子性的SQL查询,或者说一个独立的工作单元。

  事务的元素 :ACID 表示原子性(Atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability).

                      原子性:整个事务中的所有操作要么全部成功,要不全部失败,不可能只执行其中的一部分。

                      一致性:事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。

                      隔离性:一个事务所做的修改在提交前,对其他事务是不可见的,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

                      持久性:事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

3)隔离级别

      四种隔离级别:

            1. READ UNCOMMITTED(未提交读)

                        事务中的修改,即使没有提交,对其他事务也是可见的。 对应--》脏读

                        脏读:事务可以读取未提交的数据-->这也被称为脏读。

                                  如:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

             2.READ COMMITTED(提交读)

                         一个事务开始时,只能“看见”已经提交的事务所做的修改。对应--》不可重复读

                         不可重复读:指在一个事务内,多次读取同一个数据,在这个事务还没有结束 ,另一个事务也访问该同一数据,                                                但是由于第二个事务的修改,那么第一个事务两次读取的数据可能不一样。

                                   如:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A                                               多次读取同一数据时,结果不一致。

             3.REPEATABLE READ(可重复读)

                           解决了脏读,保证在同一事务中多次读取同样记录结果是一样的。--》出现了幻读

                            幻读 :指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的                                         事务再次读取该范围的记录时,会产生幻行。

                                         InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC)解决了幻读的问题。

              4.SERIALIZABLE(可串行化)

                            最高的隔离级别,通过强制事务串行执行,避免了幻读,读取每一行的数据上都加锁,可能导致大量的超时和锁竞争,实际很少用到。在要求确保数据的强一致性且可以接受没有并发的情形下才采用。

               不可重复读侧重于修改,幻读侧重于新增或删除。

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

 4)多版本并发控制  (MVCC ,Multiversion Concurrency Control )   

     mysql的大多数事务型存储引起都实现了多版本并发控制(基于并发控制的考虑),

      mysql,oracle,PostgreSQL等其他数据库系统也实现了MVCC.

      MVCC 实现由乐观并发和悲观并发控制,也就是乐观锁和悲观锁。

     InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间)。存储的不是实际时间而是系统版本号。每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

      在 可重复读的隔离级别下,MVCC具体操作。

                SELECT :-->InnoDB会根据以下两个条件检查每行记录:

                                 a、InnoDB只查找版本早于当前事务版本的数据行(也就是行的系统版本号小于或等于事务的系统版本号)。

                                       这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么事务自身插入或者修改过的。

                                 b、行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未                                          被删除。

               INSERT :-->InnoDB为新插入的每一行保存当前系统版本号作为行版本号。

               DELETE:--->为删除的每一行保存当前系统版本号作为行删除标识。

               UPDATE--->InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行                                     删除标识。

            MVCC只在可重复读和提交读两个级别下工作。其他两个隔离级别和MVCC不兼容。未提交读总是读取最新的数据行。

 5)存储引擎

               在文件系统中,mysql将每个数据库(也可以称为schema) 保存为数据目录下的一个子目录。

               创建表时,mysql会在数据库子目录下创建一个和表同名的.frm文件保存表的定义。

                如创建一个名为mytable的表,mysql会在mytable.frm文件中保存该表的定义。

           InnoDB :  是Mysql默认的事务型存储引擎。

                            InnoDB的数据存储在表空间(tablespace)中,表空间由一系列的数据文件组成。

                            InnoDB采用MVCC来支持高并发,实现了四个标准的隔离级别。其默认级别是可重复读。

                            通过间隙锁(next-key locking) 策略防止幻读的出现。

                            间隙锁使得InnoDB不仅锁定查询设计的行,还会对索引中的间隙进行锁定,以防止幻影行的插入。

                            InnoDB表时基于聚族索引建立的,聚族索引对主键查询有很高的性能,不过它的二级索引(非主键索引)中必须                                          包含主键列。所以如果主键列很大的话,其他的索引也会很大。如果索引列很大,主键列应尽可能小。

            MyISAM   :在 MySQL5.1及之前的版本,MyISAM是默认的存储引擎。MyISAM提供了大量的特性,包括全文索引,压                                     缩,空间函数(GIS)等。   MyISAM   不支持事务和行级锁。 缺陷 是崩溃后无法安全恢复。  

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

                             MyISAM表可以包含动态或者静态(长度固定)行。Mysql会根据表的定义来决定采用何种行格式。

                             MyISAM表可以存储的行记录数,一般受限于可用的磁盘空间或者操作系统中单个文件的最大尺寸。

                             特性: 加锁与并发-》 MyISAM对整张表加锁,而不是针对行,读取的时候会对需要读到的所有表加共享锁,写 入时则对表加排他锁。但是在表有读取查询的同时,也可以往表中插入新的记录。

                                       修复-》check TABLE mytable检查表错误,有错误通过REPAIR TABLE mytable修复,工具修复 myisamchk工具。

                    Archive引擎:只支持INSERT  和SELECT操作    ,支持行级锁和专用的 缓冲区。可以实现高并发的插入。

                    Blackhole引擎:没有实现任何存储机制,会丢失所有插入数据,不保存,会记录Blackhole日志。

                    CSV引擎:将普通的CSV文件作为mysql的表来处理,不支持索引。

                    Federated引擎:返回其他mysql服务器的一个代理,会创建一个到远程mysql服务器的客服端连接,并将查询传输到远程服务器执行,然后提取或者发送需要的数据。

                   Memery引擎:比MyISAM表要快一个数量级,所有数据都保存在内存中,不需要进行磁盘I/O.Memory表的结构在重启之后会保留,但数据会丢失。Memery表用于查找或者映射表(邮编),用于保存数据分析产生的中间数据,支持hash索引,是表级锁,并发性能低。

                   Merge引擎:是MyISAM的一个变种,Merge表是由多个MyISAM表合并而来的虚拟表。

                   NDB集群引擎:mysql服务器,ndb集群存储引擎,以及分布式,share-nothing,容灾的,高可用的ndb数据库的组合称为Mysql集群。

6)优化数据类型

        尽量选择最小的数据类型,占用更少的内存,磁盘和cpu资源,

        整型比字符操作代价更低,因为字符集和校对规则使字符比整型更加复杂。

        尽量避免null,通常情况下最好指定列为NOT NULL,可为null的列会使用更多的存储空间,为NULL的列使得索引、索引统计和值都比较复杂,当可为NULL的列被索引时,每个索引记录需要一个额外的字节,在MYISAM里可能导致固定大小的索引变成可变大小的索引。通常把 可为NULL的列改为NOT NULL带来的性能提升比较小。除非确实会导致问题才去改。

猜你喜欢

转载自blog.csdn.net/Jacabe/article/details/82810658