美文网首页
数据库常见问题

数据库常见问题

作者: 关耳木水 | 来源:发表于2018-08-15 17:55 被阅读0次

    MyISAM和InnoDB


    主要区别:

    1).[事务]MyISAM是非事务安全型的,而InnoDB是事务安全型的,默认开启自动提交,宜合并事务,一同提交,减小数据库多次提交导致的开销,大大提高性能。
    2).[锁]MyISAM锁的粒度是表级,而InnoDB支持行级锁定。
    3).[全文索引]MyISAM支持全文类型索引,而InnoDB不支持全文索引。
    4).[查询效率]MyISAM相对简单,所以在效率上要优于InnoDB,小型应用可以考虑使用MyISAM。
    5).[外健]MyISAM不支持外健,InnoDB支持。
    6).[count]MyISAM保有表的总行数,InnoDB只能遍历。
    6).MyISAM表是保存成文件的形式,在跨平台的数据转移中使用MyISAM存储会省去不少的麻烦。
    7).InnoDB表比MyISAM表更安全,可以在保证数据不会丢失的情况下,切换非事务表到事务表(alter table tablename type=innodb)。
    8)MyIsam索引和数据分离,InnoDB在一起,MyIsam天生非聚簇索引,最多有一个unique的性质,InnoDB的数据文件本身就是主键索引文件,这样的索引被称为“聚簇索引”
    9)InnoDB提供多版本数据支持 ,MyIsam不支持
    10)两者都仅支持B+树索引,不支持hash索引

    应用场景:
    1).MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。
    2).InnoDB用于事务处理应用程序,具有众多特性,包括ACID事务支持。如果应用中需要执行大量的INSERT或UPDATE操作,则应该使用InnoDB,这样可以提高多用户并发操作的性能。


    数据库索引


    (一)在了解数据库索引之前,首先了解一下数据库索引的数据结构基础,B+tree

    B+tree 是一个n叉树,每个节点有多个叶子节点,一颗B+树包含根节点,内部节点,叶子节点。根节点可能是一个叶子节点,也可能是一个包含两个或两个以上叶子节点的节点。

    B+tree的性质:

    1.n棵子tree的节点包含n个关键字,不用来保存数据而是保存数据的索引。

    2.所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。

    3.所有的非终端结点可以看成是索引部分,结点中仅含其子树中的最大(或最小)关键字。

    B+tree结构原型图大概如下(引用):


    image

    由于B+tree的性质, 它通常被用于数据库和操作系统的文件系统中。NTFS, ReiserFS, NSS, XFS, JFS, ReFS 和BFS等文件系统都在使用B+树作为元数据索引,因为B+ 树的特点是能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度(B+ 树元素自底向上插入)。

    (二)数据库索引

    数据库索引是用于提高数据库表的数据访问速度的。

    数据库索引的特点:

    a)避免进行数据库全表的扫描,大多数情况,只需要扫描较少的索引页和数据页,而不是查询所有数据页。而且对于非聚集索引,有时不需要访问数据页即可得到数据。

    b)聚集索引可以避免数据插入操作,集中于表的最后一个数据页面。

    c)在某些情况下,索引可以避免排序操作。

    聚集(clustered)索引,也叫聚簇索引。

    定义:数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。

    一、为什么要创建索引呢(优点)?
    这是因为,创建索引可以大大提高系统的性能。
    第一, 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
    第二, 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
    第三, 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
    第四, 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
    第五, 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

    二、建立方向索引的不利因素(缺点)
    也许会有人要问:增加索引有如此多的优点,为什么不对表中的每一个列创建一个索引呢?这种想法固然有其合理性,然而也有其片面性。虽然,索引有许多优点,但是,为表中的每一个列都增加索引,是非常不明智的。这是因为,增加索引也有许多不利的一个方面。

    第一, 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
    第二, 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
    第三, 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

    三、创建方向索引的准则
    索引是建立在数据库表中的某些列的上面。因此,在创建索引的时候,应该仔细考虑在哪些列上可以创建索引,在哪些列上不能创建索引。
    一般来说,应该在这些列上创建索引。
    第一, 在经常需要搜索的列上,可以加快搜索的速度;
    第二, 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
    第三, 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
    第四, 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
    第五, 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
    第六, 在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。


    数据库优化


    一、百万级数据库优化方案

    1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

    2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描

    3.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。

    4.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描

    5.in和 not in 也要慎用,否则会导致全表扫描

    6.下面的查询也将导致全表扫描:

       select id from t where name like ‘%abc%’
    

    7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。

    8.应尽量避免在 where子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。

    9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。

    SQL什么条件会使用索引?

    当字段上建有索引时,通常以下情况会使用索引:

    INDEX_COLUMN = ?

    INDEX_COLUMN > ?

    INDEX_COLUMN >= ?

    INDEX_COLUMN < ?

    INDEX_COLUMN <= ?

    INDEX_COLUMN between ? and ?

    INDEX_COLUMN in (?,?,...,?)

    INDEX_COLUMN like ?||'%'(后导模糊查询)

    T1. INDEX_COLUMN=T2. COLUMN1(两个表通过索引字段关联)

    分库分表

    分库分表的目的就是讲一个数据库切分成多个部分放到不同的数据库上,以便缓解单一数据库的性能问题。

    举个例子吧,当你面对海量数据的数据库时,若归因为表多导致的数据量大的话,建议采用垂直切分,就是把关系紧密(比如一个应用模块的表)的表

    放在一个数据库(server)。如果表并不多,但是每张表的数据非常的多,那就要采用水平切分了。就是将表按照某种规则(常用方法是按ID散列)切分到多个数据库(server)上。当然这只是举了一个例子,因为现实情况要比这个复杂,需要将两种切分方式联合使用才能使得系统性能更优(因为可能一张表的数据量很大,超出了一台服务器的能力范围,这时候就要在垂直拆分的基础上再进行水平拆分)。

    数据库的垂直切分和水平切分

    垂直切分:就是按功能模块拆分,比如分为订单库,商品库,用户库。垂直切分最大的特点就是简单明了,实施方便。
    
    水平切分:将同一个表的数据进行分块保存到不同的数据库。
    
    上面呢是两个概念,我们来看一个具体的例子,有助于我们理解:
    

    案例:简单购物系统,涉及以下几张表

    1、产品表(数据量10w,稳定)

    2、订单表(数据量200W,且有增长趋势)

    3、用户表(数据量100w,且有增长趋势)

    以mysql为例讲述下水平拆分和垂直拆分,mysql数据库能容忍的数据量级在百万静态数据到千万

    垂直拆分:

    解决问题:表与表之间的io竞争

    不解决的问题:但表中数据量增长出现的压力

    方案:把产品表和用户表放到一个server上,订单表单独放到一个server上

    水平拆分:

    解决问题:单表中数据量增长出现的压力

    不解决的问题:表与表之间的io竞争

    方案:用户表通过性别拆分为男用户表和女用户表;订单表通过已完成和完成中拆分为已完成订单和未完成订单;产品表未完成订单放一个server上,已完成订单表和男用户表放一个server上,女用户表放一个server上(女的爱购物,数据增量大)


    ACID与事物


    一个事务本质上有四个特点ACID:

    Atomicity原子性
    Consistency一致性
    Isolation隔离性
    Durability耐久性
    

    原子性

    原子性任务是一个独立的操作单元,是一种要么全部是,要么全部不是的原子单位性的操作。
    一致性

    一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。

    一致性有下面特点:

    如果一个操作触发辅助操作(级联,触发器),这些也必须成功,否则交易失败。
    如果系统是由多个节点组成,一致性规定所有的变化必须传播到所有节点(多主复制)。如果从站节点是异步更新,那么我们打破一致性规则,系统成为“最终一致性”。
    一个事务是数据状态的切换,因此,如果事务是并发多个,系统也必须如同串行事务一样操作。

    在现实中,事务系统遭遇并发请求时,这种串行化是有成本的, Amdahl法则描述如下:它是描述序列串行执行和并发之间的关系。

    “一个程序在并行计算情况下使用多个处理器所能提升的速度是由这个程序中串行执行部分的时间决定的。”

    大多数数据库管理系统选择(默认情况下)是放宽一致性,以达到更好的并发性。

    隔离性

    事务是并发控制机制,他们交错使用时也能提供一致性。隔离让我们隐藏来自外部世界未提交的状态变化,一个失败的事务不应该破坏系统的状态。隔离是通过用悲观或乐观锁机制实现的。

    耐久性

    一个成功的事务将永久性地改变系统的状态,所以在它结束之前,所有导致状态的变化都记录在一个持久的事务日志中。如果我们的系统突然受到系统崩溃或断电,那么所有未完成已提交的事务可能会重演。

    事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。


    mysql


    Mysql的索引的类型

    Mysql目前主要有以下几种索引类型:
    FULLTEXT,HASH,BTREE,RTREE

    FULLTEXT

    即为全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。值得一提的是,在数据量较大时候,现将数据放入一个没有全局索引的表中,然后再用CREATE INDEX创建FULLTEXT索引,要比先为一张表建立FULLTEXT然后再将数据写入的速度快很多。

    HASH

    由于hash索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。那为什么还需要其他的树形索引呢?
    (1)Hash 索引仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询。
    由于 Hash 索引比较的是进行 Hash 运算之后的 Hash 值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的大小关系,并不能保证和Hash运算前完全一样。
    (2)Hash 索引无法被用来避免数据的排序操作。
    由于 Hash 索引中存放的是经过 Hash 计算之后的 Hash 值,而且Hash值的大小关系并不一定和 Hash 运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算;
    (3)Hash 索引不能利用部分索引键查询。
    对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再一起计算 Hash 值,而不是单独计算 Hash 值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用。
    (4)Hash 索引在任何时候都不能避免表扫描。
    前面已经知道,Hash 索引是将索引键通过 Hash 运算之后,将 Hash运算结果的 Hash 值和所对应的行指针信息存放于一个 Hash 表中,由于不同索引键存在相同 Hash 值,所以即使取满足某个 Hash 键值的数据的记录条数,也无法从 Hash 索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。
    (5)Hash 索引遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高。
    对于选择性比较低的索引键,如果创建 Hash 索引,那么将会存在大量记录指针信息存于同一个 Hash 值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据的访问,而造成整体性能低下。

    BTREE

    BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中,如二叉树一样,每次查询都是从树的入口root开始,依次遍历node,获取leaf。

    BTREE在MyISAM里的形式和Innodb稍有不同

    在 Innodb里,有两种形态:一是primary key形态,其leaf node里存放的是数据,而且不仅存放了索引键的数据,还存放了其他字段的数据。二是secondary index,其leaf node和普通的BTREE差不多,只是还存放了指向主键的信息.

    而在MyISAM里,主键和其他的并没有太大区别。不过和Innodb不太一样的地方是在MyISAM里,leaf node里存放的不是主键的信息,而是指向数据文件里的对应数据行的信息.

    RTREE

    TREE在mysql很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。

    相对于BTREE,RTREE的优势在于范围查找.

    各种索引的使用情况
    (1)对于BTREE这种Mysql默认的索引类型,具有普遍的适用性

    (2)由于FULLTEXT对中文支持不是很好,在没有插件的情况下,最好不要使用。其实,一些小的博客应用,只需要在数据采集时,为其建立关键字列表,通过关键字索引,也是一个不错的方法,至少愚安我是经常这么做的。

    (3)对于一些搜索引擎级别的应用来说,FULLTEXT同样不是一个好的处理方法,Mysql的全文索引建立的文件还是比较大的,而且效率不是很高,即便是使用了中文分词插件,对中文分词支持也只是一般。真要碰到这种问题,Apache的Lucene或许是你的选择。

    (4)正是因为hash表在处理较小数据量时具有无可比拟的素的优势,所以hash索引很适合做缓存(内存数据库)。如mysql数据库的内存版本Memsql,使用量很广泛的缓存工具Mencached,NoSql数据库redis等,都使用了hash索引这种形式。当然,不想学习这些东西的话Mysql的MEMORY引擎也是可以满足这种需求的。

    mysql事物隔离性

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

    mysql默认的事务隔离级别为repeatable-read

    Mysql(Innodb)如何避免幻读
    幻读问题是指一个事务的两次不同时间的相同查询返回了不同的的结果集。例如:一个 select 语句执行了两次,但是在第二次返回了第一次没有返回的行,那么这些行就是“phantom” row.

    创建了一个以SELECT操作的时间为基准点的 read view避免了幻读的产生
    一致性读是通过 MVCC 为查询提供了一个基于时间的点的快照。这个查询只能看到在自己之前提交的数据,而在查询开始之后提交的数据是不可以看到的。一个特例是,这个查询可以看到于自己开始之后的同一个事务产生的变化。这个特例会产生一些反常的现象
    InnoDB通过Nextkey lock解决了当前读时的幻读问题
    Next-Key Lock:
    行锁与间隙锁组合起来用就叫做Next-Key Lock。锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。

    相关文章

      网友评论

          本文标题:数据库常见问题

          本文链接:https://www.haomeiwen.com/subject/sjbwbftx.html