• mysql第一章 存储引擎和索引


    第一章 mysql之索引

    1.索引的定义:索引是为了加速对表中数据行的检索而创建的一种分散存储的数据结构。

    2.我们为什么要使用索引:

     a.极大的减少存储引擎需要扫描的数据量。

     b.帮助我们将随机IO变为顺序IO。

     c.帮助我们在进行分组,排序等的操作时避免使用临时表。

    3.使用索引时我们需要注意什么:

     a.需要考虑列的离散性,列的离散性越高,选择性就越好。

     b.考虑最左匹配原则,对索引中关键字的匹配一定是从左往右依次匹配,且不可跳过。

     c.创建联合索引的优先原则:最常用的列优先(最左匹配),选择性高的列优先(列的离散度),宽度小的列优先(最少空间原则)。

     d.如果查询列可以通过索引的关键字直接返回,则该索引被称之为覆盖索引。所以我们在查询时应该避免使用select * 之类的查询,尽量让查询字段使用到覆盖索引,以提升查询性能(减少了

    io交互次数)。

    第二章 mysql之存储引擎

    1.mysql存储引擎的特点

     a.插拔式的插件方式。

     b.mysql的存储引擎是在指定的表之上的,即一个数据库的每个表都可以指定单独的存储引擎。

     c.无论是哪种存储引擎,相同点是都会指定一个.frm表结构定义描述文件。

    2.mysql各个存储引擎及其特点

    2.1 CSV存储引擎

     特点:

      a.数据存储使用csv文件。

      b.不能定义索引。

      c.列的定义必须为not null。

      d.不能够设置自增列。(不适用于大表或者数据的在线处理。)

      e.csv数据的存储用,隔开,可以直接编辑csv文件对数据进行编排。(数据的安全性比较低。)

      注意:编辑之后要使数据生效,可以使用flush table XXX命令。  

     应用场景:

      a.数据的快速导入导出;

      b.表格直接转换成为csv。

    2.2 Archive存储引擎

     特点:

      a.压缩协议进行的数据存储,数据存储为ARZ文件格式。

      b.只支持insert和select两种操作,并且只允许自增id建立索引。

      c.行级锁(同InnoDB),不支持事物,数据占用磁盘少。

     应用场景:

      a.日志系统;

      b.大量的设备数据采集。       

    2.3 Memory(heap)存储引擎

     特点:

      a.数据都是存储在内存中,IO效率要比其他引擎高很多,服务重启数据丢失,内存数据表默认只有16M。

      b.支持hash索引,B tree索引,默认hash(查找复杂度0(1))。

      c.字段长度都是固定长度varchar(32)=char(32)。

      d.不支持大数据存储类型字段如 blog,text。

      e.表级锁。

     应用场景:

      a.等值查找热度较高数据。

      b.查询结果内存中的计算,大多数都是采用这种存储引擎 作为临时表存储需计算的数据。

    2.4 Myisam

     特点:

      a.Mysql5.5版本之前的默认存储引擎。较多的系统表也还是使用这个存储引擎。系统临时表也会用到Myisam存储引擎。

      b.select count(*) from table  无需进行数据的扫描(在内部做了优化)。

      c.数据(MYD)和索引(MYI)分开存储。

      d.表级锁,不支持事物。

    2.5 InnoDB(后续围绕InnoDB存储引擎介绍)

     特点:

      a.Mysql5.5及以后版本的默认存储引擎 。

      b.行级锁,支持事物。

      c.聚集索引(主键索引)方式进行数据存储。

      d.支持外键关系保证数据完整性。

    可以使用命令 show enginesg来查看当前使用的mysql数据库支持的存储引擎,如图所示

    第三章 mysql查询优化

    说明:mysql的查询执行路径如下图所示,后面就1-5做具体说明。

    mysql客户端和服务端的通信

     通信协议,客户端和服务端采用半双工的通信方式。特点是客户端一旦开始发送消息,另一端得等消息发送完才能够响应。客户端一旦开始接收数据就没法停下来发送指令。

     通信状态,客户端与服务端的通信状态有以下几种,具体的通信状态可以通过命令,show processlist查看,如下图所示。 

      Sleep:线程正在等待客户端发送数据。

      Query:连接线程正在执行查询。

      Locked:线程正在等待表锁的释放。

      Sorting result:线程正在对结果进行排序。

      Sending data:向请求端返回数据。

      说明:可通过kill {id}的方式进行连接的杀掉。

    查询缓存

    工作原理:缓存SELECT操作的结果集和SQL语句;新的SELECT语句,先去查询缓存,判断是否存在可用的记录集。

    判断标准:与缓存的SQL语句,是否完全一样,区分大小写 (简单认为存储了一个key-value结构,key为sql,value为sql查询结果集)。

    可以通过show variables like 'query_cache%'命令查看mysql缓存设置状态。如图:

     

    各个参数简要说明:

     query_cache_type

      值:0 -– 不启用查询缓存,默认值。

      值:1 -– 启用查询缓存,只要符合查询缓存的要求,客户端的查询语句和记录集都可以缓存起来,供其他客户端使用,加上SQL_NO_CACHE将不缓存。

      值:2 -– 启用查询缓存,只要查询语句中添加了参数:SQL_CACHE,且符合查询缓存的要求,客户端的查询语句和记录集,则可以缓存起来,供其他客户端使用。

     query_cache_size

      允许设置query_cache_size的值最小为40K,默认1M,推荐设置 为:64M/128M。

     query_cache_limit

      限制查询缓存区最大能缓存的查询记录集,默认设置为1M。

    show status like 'Qcache%' 命令可查看缓存的详细信息。

    查询缓存时,以下情况不会缓存。

     1.当查询语句中有一些不确定的数据时,则不会被缓存。如包含函数NOW(), CURRENT_DATE()等类似的函数,或者用户自定义的函数,存储函数,用户变量等都不会被缓存。

     2.当查询的结果大于query_cache_limit设置的值时,结果不会被缓存。

     3.对于InnoDB引擎来说,当一个语句在事务中修改了某个表,那么在这个事务提交之前,所有与这个表相关的查询都无法被缓存。因此长时间执行事务,会大大降低缓存命中率。

     4.查询的表是系统表。

     5.查询语句不涉及到表。

    查询缓存的缺陷(mysql默认关闭了缓存)

     1.在查询之前必须先检查是否命中缓存,浪费计算资源。

     2.如果这个查询可以被缓存,那么执行完成后,MySQL发现查询缓存中没有这个查询,则会将结果存入查询缓存,这会带来额外的系统消耗。

     3.针对表进行写入或更新数据时,将对应表的所有缓存都设置失效。

     4.如果查询缓存很大或者碎片很多时,这个操作可能带来很大的系统消耗

    查询缓存适用的场景

     1.以读为主的业务,数据生成之后就不常改变的业务。

     2.比如门户类、新闻类、报表类、论坛类等。

    查询优化处理(包含了解析,预处理,查询优化)

    解析sql:通过lex词法分析,yacc语法分析将sql语句解析成解析树。可参考:https://www.ibm.com/developerworks/cn/linux/sdk/lex/ 

    预处理阶段:根据mysql的语法的规则进一步检查解析树的合法性,如:检查数据的表 和列是否存在,解析名字和别名的设置。还会进行权限的验证。

    查询优化器

     优化器的主要作用就是找到最优的执行计划。

     找到最优执行计划的原则 

      使用等价变化规则。
       5 = 5 and a > 5 改写成 a > 5
       a < b and a = 5 改写成 b > 5 and a = 5
       基于联合索引,调整条件位置等
      优化count 、min、max等函数 min函数只需找索引最左边 max函数只需找索引最右边 myisam引擎count(*)。

      覆盖索引扫描。 

      子查询优化。

      提前终止查询用了limit关键字或者使用不存在的条件。

      IN的优化先进行排序,再采用二分查找的方式。

    Mysql的查询优化器是基于成本计算的原则。他会尝试各种执行计划。 数据抽样的方式进行试验(随机的读取一个4K的数据块进行分析)。

    mysql查询优化之执行计划

      在mysql中,使用explain关键字可以查看sql的执行计划。例如:explain select count(*) from usersG语句就可以查看语句select count(*) from users的执行计划。而通过explain关键字,输出的信息一般有下面几个字段。

      id:表示select查询的序列号,标识查询的顺序。规则为

       1.若id相同,执行顺序由上至下。

       2.若id不同,如果是子查询,id的序号会自增,id值越大,优先级越高,越先会被执行。

       3.id相同又不同,即两种情况同时存在,id如果相同,可以认为是一组,从上往下顺序执行。在所有的组中,id值越大,优先级越高,越先会被执行。

      select_type:表示查询的类型,主要区分普通查询,联合查询,子查询等。值有:

       SIMPLE:简单的select查询,查询中不包含子查询或者union。

       PRIMARY:查询中包含子部分,最外层查询则被标记为primary。

       SUBQUERY/MATERIALIZED:SUBQUERY表示在select 或 where列表中包含了子查询。MATERIALIZED表示where 后面in条件的子查询。

       UNION:若第二个select出现在union之后,则被标记为union。

       UNION RESULT:从union表获取结果的select。

      table:表示查询涉及到的表。直接显示表名或者表的别名。   

       <unionM,N> 由ID为M,N 查询union产生的结果
       <subqueryN> 由ID为N查询生产的结果

      type:访问类型,sql优化中一个很重要的指标。结果值从好到坏依次是:system > const > eq_ref > ref > range > index > ALL

       system:表只有一行记录(等于系统表),const类型的特例,基本不会出现,可以忽略不计。

       const:表示通过索引一次就找到了,const用于比较primary key或者unique索引。

       eq_ref:唯一索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。

       ref:非唯一性索引扫描,返回匹配某个单独值的所有行,本质是也是一种索引访问。

       range:只检索给定范围的行,使用一个索引来选择行。

       index:Full Index Scan,索引全表扫描,把索引从头到尾扫一遍。

       ALL:Full Table Scan,遍历全表以找到匹配的行。

      possible_keys:查询过程中有可能用到的索引。

      key:实际使用的索引,如果为NULL,则没有使用索引 。

      rows:根据表统计信息或者索引选用情况,大致估算出找到所需的记录所需要读取的行数。

      filtered:它指返回结果的行占需要读到的行(rows列的值)的百分比 表示返回结果的行数占需读取行数的百分比,filtered的值越大越好。

      Extra:十分重要的额外信息。  

       1、Using filesort:mysql对数据使用一个外部的文件内容进行了排序,而不是按照表内的索引进行排序读取。
       2、Using temporary:使用临时表保存中间结果,也就是说mysql在对查询结果排序时使用了临时表,常见于order by 或 group by。
       3、Using index:表示相应的select操作中使用了覆盖索引(Covering Index),避免了访问表的数据行,效率高。 
       4、Using where:使用了where过滤条件。
       5、select tables optimized away:基于索引优化MIN/MAX操作或者MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段在进行计算,查询执行计划生成的阶段即可完成优化。

    第三章 mysql事物

      事物定义:数据库操作的最小工作单元,是作为单个逻辑工作单元而执行的一系列的操作。事物是一组不可在分割的操作集合(工作逻辑单元)。

      事物的ACID特性:

       A(原子性,Atomicity):最小的工作单元,整个工作单元要么一起提交成功,要么一起失败回滚。

       C(一致性,Consistency):事物中操作的数据的状态是一致的。即写入资料的结果必须完全符合预设的规则,不会因为出现系统意外等原因导致状态的不一致。

       I(隔离性,Isolation):一个事务所操作的数据在提交之前,对其他事务的可见性设定(一般设定为不可见)。

       D(持久性,Durability):事务所做的修改就会永久保存,不会因为系统意外导致数据的丢失。

      事物的四种隔离级别:

       Read Uncommited(读未提交):事物未提交对其它的事物也是可见的。(造成脏读) --未解决并发问题

       Read Commited(提交读):一个事物开始之后,只能看到自己事物所做提交的修改,不可重复读。 --解决脏读问题

       Repeatable Read(可重复读):在同一个事物中多次读取同样的数据结果是一样的。这种隔离级别未解决幻读问题。 --解决了不可重复读的问题

       Serializable(串行化):最高的隔离级别,通过强制事物的串行执行。--解决了所有的问题。

    第四章 隔离级别的实现手段之数据库锁

     锁是为了管理不同事物对同一资源的并发访问。InnoDB存储引擎支持行锁和表锁(一种另类的行锁)。

     表锁和行锁的区别:锁定力度:表锁 < 行锁  加锁效率:表锁 < 行锁  冲突概率:表锁 > 行锁  并发性能:表锁 > 行锁

     MySql的InnoDB存储引擎的锁类型:

      共享锁(行锁):Shared Locks

      排他锁(行锁):Exclusive Locks 

      意向锁共享锁(表锁):Intention Shared  Locks 

      意向锁排他锁(表锁):Intention Exclusive Locks 

      自增锁:AUTO-INC Locks

     行锁的算法:

      临键锁 Next-key Locks :当sql执行按照索引进行数据检索,并且查询条件为范围查找(between and, <, >等),且有数据命中时。则此时sql语句加上的锁为临键锁,锁住索引的记录+区间(左

    开右闭)。例如:假设现在有数据表user_lock,表中有字段id,name,age,其中id为主键索引,表中现在有九条记录。

      

      现在执行如下的语句,表示开启一个事物,并查询id在3-7之间的数据,这样的操作会锁住表的区间为(3,7]和(7,9]。

      BEGIN; select * from user_lock where id > 3 and id < 7 for update;

      

      现在在另一个窗口执行下面的语句。

      

      

      我们总共执行了两个更新语句,发现id在(3,7]和(7,9]区间内的无法执行,而id=2的更新语句成功执行了。证明了间隙锁锁住了(3,7]和(7,9]区间。当执行commit操作时,这个区间锁将会被释放。

     间隙锁 Gap Locks:当sql执行按照索引进行数据的检索时,查询条件的数据不存在,这时SQL语句加上的锁即为 Gap locks,锁住索引不存在的区间(左开右开)。

     录锁 Record Locks:当sql执行按照唯一性(Primary key、Unique key)索引进行数据的检索时,查询条件等值匹 配且查询的数据是存在,这时SQL语句加上的锁即为记录锁Record

    locks,锁住具体的索引项。

     共享锁:又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁, 都能访问到数据,但是只能读不能修改;加锁释锁方式:select * from users WHERE

    id=1 LOCK IN SHARE MODE; commit/rollback。

     排他锁:又称为写锁,简称X锁,排他锁不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的锁(共享锁、排他锁),只有该获取了排他锁的事务是可以

    对数据行进行读取和修改,(其他事务要读取数据可来自于快照)。加锁释锁方式: delete / update / insert 默认加上X锁 SELECT * FROM table_name WHERE ... FOR UPDATE

    commit/rollback。

     InnoDB存储引擎行锁到底做了些什么:InnoDB是通过给索引上的索引项加锁来实现的。只有通过索引条件进行数据检索,InnoDB才会使用行级锁。否则InnoDB将会使用表锁(锁住索引的所有记录)。

     表锁:lock tables xx read/write。

     意向共享锁(IS):表示事务准备给数据行加入共享锁,即一个数据行加共享锁前必须先取得该表的IS锁,意向共享锁之间是可以相互兼容的。

     意向排他锁(IX):表示事务准备给数据行加入排他锁,即一个数据行加排他锁前必须先取得该表的IX锁,意向排它锁之间是可以相互兼容的。

     意向锁(IS、IX)是InnoDB数据操作之前自动加的,不需要用户干预。

     意向锁存在的意义当事务想去进行锁表时,可以先判断意向锁是否存在,存在时则可快速返回该表不能启用表锁。

     自增锁AUTO-INC Locks:   

      针对自增列自增长的一个特殊的表级别锁。

      show variables like 'innodb_autoinc_lock_mode';

      默认取值1,代表连续,事务未提交ID永久丢失。

    第五章 隔离级别的实现手段之MVCC

     mysql在多个事物并发情况下容易出现下列问题:

      脏读:在A事物执行过程中,读取到了事物B回滚的数据。

      不可重复读:假设数据库有一条id=1的记录name=update。事物A在第一次读取的时候,name=update,但是当事物A在第二次读取的时候,发现name=update1了。其原因在于事物A在第一次和第

    二次执行期间执行了事物B。

      幻读:假设数据库usrs表现在有5条记录,事物A在第一次查询的时候,返回了五条记录,但是第二次查询的时候,发现多了两条记录。其原因在于事物A在第一次和第二次执行的时候执行了事

    物B。

      说明:脏读指的是读取到了回滚的数据。但是不可重复读和幻读读取到的是提交后的数据,但是这两者最主要的区别在于关注点不同,不可重复读关注的是修改,而幻读关注

    的是新增和删除。

      mysql事物的隔离级别:

        脏读(未解决脏读问题)  

        不可重复读 (解决了脏读问题)

        可重复读(解决了不可重复读的问题)--mysql的默认事物隔离级别

        串行化(解决了幻读的问题)

     MVCC:多版本并发控制。并发访问(读或写)数据库时,对正在事务内处理的数据做多版本的管理。以达到用来避免写操作的堵塞,从而引发读操作的并发问题。

  • 相关阅读:
    【leetcode】500. Keyboard Row
    【排序算法汇总】5类8种排序算法
    【leetcode】339. Nested List Weight Sum
    ArcCatalog中将SQLServer中的空间数据导入到Oracle库中
    初学ArcGIS API for JavaScript
    ArcGIS API for JavaScript开发环境配置
    shapefile与gdb中不能允许存在的几何错误
    C#中的Dictionary字典类介绍(转载)
    泛型Dictionary<string,string>的用法
    空间数据存储格式wkb和wkt(转载)
  • 原文地址:https://www.cnblogs.com/code-star/p/10671801.html
Copyright © 2020-2023  润新知