(1)InnoDB存储引擎支持事务,而MyISAM不支持事务;html
(2)InnoDB支持行级锁,而MyISAM只支持表级锁;前端
( InnoDB行锁是经过给索引加锁实现的,即只有经过索引条件检索数据,InnoDB才使用行级锁,不然将使用表级锁!行级锁在每次获取锁和释放锁的操做须要比表级锁消耗更多的资源。mysql
MySQL表级锁有两种模式:表共享读锁和表独占写锁。就是说对MyIASM表进行读操做时,它不会阻塞其余用户对同一表的读请求,但会阻塞对同一表的写操做;而对MyISAM表的写操做,会阻塞其余用户对同一表的读和写操做。)程序员
(3)InnoDB支持外键,而MyISAM不支持外键;面试
(4)InnoDB不保存数据库表中表的具体行数,而MyISAM会保存;算法
( 也就是说,执行 select count(*) from table 时,InnoDB要扫描一遍整个表来计算有多少行,而MyISAM只须要读出保存好的行数便可(内部维护了一个计算器,能够直接调取)。【注】:当count(*)
语句包含where
条件时,两种表的操做是同样的。也就是上述介绍到的InnoDB使用表锁的一种状况。)sql
对于select ,update ,insert ,delete 操做:mongodb
若是执行大量的SELECT,MyISAM是更好的选择(由于MyISAM不支持事务,使得MySQL能够提供高速存储和检索,以及全文搜索能力);数据库
若是执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表(由于InnoDB支持事务,在一些列增删改中只要哪一个出错还能够回滚还原,而MyISAM就不能够了)。编程
插入缓冲、二次写、自适应哈希索引、预读
(1)插入缓冲:
通常状况下,主键是行惟一的标识符。一般应用程序中行记录的插入顺序是按照主键递增的顺序进行插入的。所以,插入汇集索引通常是顺序的,不须要磁盘的随机读取。由于,对于此类状况下的插入,速度仍是很是快的。
若是索引是非汇集的且不惟一,在进行插入操做时,数据的存放对于非汇集索引叶子节点的插入不是顺序的,这时须要离散地访问非汇集索引页,因为随机读取的存在而致使了插入操做性能降低。(这是由于B+树的特性决定了非汇集索引插入的离散性。)
插入缓冲对于非汇集索引的插入和更新操做,不是每一次直接插入索引页中,而是先判断插入的非汇集索引页是否在缓存池中。若是在,则直接插入;若是不在,则先放入一个插入缓冲区中,好似欺骗数据库这个非汇集的索引已经插入到叶子结点了,而后再以必定的频率执行插入缓冲和非汇集索引页子节点的合并操做,这时一般能将多个插入合并到一个操做中(由于在一个索引页中),这就大大提升了对非汇集索引执行插入和修改操做的性能。
插入缓冲的使用要知足两个条件:
存在的问题:
在写密集的状况下,插入缓冲会过多的占用缓冲池内存,默认状况下最大能够占用1/2的缓冲池内存。
(2)二次写
当数据库宕机时,可能发生数据库正在写一个页面,而这个页只写了一部分的状况,咱们称之为部分写失效。当写入失效发生时,先经过页的副原本还原该页,再重作日志,这就是两次写。
doublewrite步骤:
若是操做系统在将页写入磁盘的过程当中崩溃了,在恢复过程当中,InnoDB存储引擎能够从共享表空间中的doublewrite中找到该页的一个副本,将其拷贝到表空间文件,再应用重作日志,就完成了恢复过程。由于有副本因此也不担忧表空间中数据页是否损坏。
(3)自适应哈希索引
InnoDB存储引擎会监控对表上索引的查找,若是观察到创建哈希索引能够带来速度的提高,则创建哈希索引,因此称为自适应的。自适应哈希索引经过缓冲池的B+树构造而来,所以创建的速度很快,并且不须要将整个表都建哈希索引,InnoDB存储引擎会自动根据访问的频率和模式来为某些页创建哈希索引。
(4)预读
MySQL的存储引擎InnoDB使用重作日志(redo log)保证一致性与持久性,回滚日志(undo log)保证原子性,使用各类锁来保证隔离性。
MySQL中有六种日志文件,分别是:
重作日志(redo log) 回滚日志(undo log) 二进制日志(binlog) 错误日志(errorlog) 慢查询日志(slow query log) 通常查询日志(general log) 中继日志(relay log)
其中重作日志和回滚日志与事务操做息息相关,二进制日志也与事务操做有必定的关系。事务是如何经过日志来实现的?
Undo 记录某 数据 被修改 前 的值,能够用来在事务失败时进行 rollback;
Redo 记录某 数据块 被修改 后 的值,能够用来恢复未写入 data file 的已成功事务更新的数据。
即,
- Redo Log 保证事务的持久性
- Undo Log 保证事务的原子性(在 InnoDB 引擎中,还用 Undo Log 来实现 MVCC)
好比某一时刻数据库 DOWN 机了,有两个事务,一个事务已经提交,另外一个事务正在处理。数据库重启的时候就要根据日志进行前滚及回滚,把已提交事务的更改写到数据文件,未提交事务的更改恢复到事务开始前的状态。即 经过 redo log 将全部已经在存储引擎内部提交的事务应用 redo log 恢复, 全部已经 prepared 可是没有 commit 的事务将会应用 undo log 作回滚。
redo log在事务没有提交前,会记录每个修改操做变动后的数据。主要是防止在发生故障的时间点,尚有脏页未写入磁盘。在重启mysql服务的时候,根据redo log进行重作,从而达到事务的持久性这一特性。(做用)
在事务提交前,只要将 Redo Log 持久化便可,不须要将数据持久化。当系统崩溃时,系统能够根据redo Log的内容,将全部数据恢复到最新的状态。(持久化:先将重作日志写入缓存,再刷新(fsync)到磁盘)
重作日志是物理日志,记录的是对于每一个页的修改。事务开始后Innodb存储引擎先将重作日志写入缓存(innodb_log_buffer)中。而后会经过如下三种方式将innodb日志缓冲区的日志刷新到磁盘。
当事务提交时,必须先将该事务的全部日志写入到重作日志文件进行持久化。
一、内容:
物理格式的日志,记录的是物理数据页面的修改的信息,其redo log是顺序写入redo log file的物理文件中去的。
二、redo log是何时写盘的?
是在事物开始以后逐步写盘的。
事务开始以后就产生redo log,redo log的写盘并非随着事务的提交才写入的,而是在事务的执行过程当中,便开始写入redo log文件中。(先将重作日志写入缓存,将日志缓冲区的日志刷新到磁盘,写入磁盘的方式有上面3种)
【注】即便某个事务尚未提交,Innodb存储引擎仍然每秒会将重作日志缓存刷新到重作日志文件。这一点是必需要知道的,由于这能够很好地解释再大的事务的提交(commit)的时间也是很短暂的。
三、何时释放:
当对应事务的脏页写入到磁盘以后,redo log的使命也就完成了,重作日志占用的空间就能够重用(被覆盖)。
保存了事务发生以前的数据的一个版本,能够用于回滚,同时能够提供多版本并发控制下的读(MVCC),也即非锁定读。(做用)
事务发生异常须要回滚,这时就须要回滚日志。回滚日志不一样于重作日志,它是逻辑日志,对数据库的修改都逻辑的取消了。当事务回滚时,它实际上作的是与先前相反的工做。对于每一个INSERT,InnoDB存储引擎都会完成一个DELETE;对于每一个UPDATE,InnoDB存储引擎都会执行一个相反的UPDATE。
未提交的事务和回滚了的事务也会产生重作日志。InnoDB存储引擎会重作全部事务包括未提交的事务和回滚了的事务,而后经过回滚日志回滚那些未提交的事务。使用这种策略须要回滚日志在重作日志以前写入磁盘,使得持久化变得复杂起来。为了下降复杂度,InnoDB存储引擎将回滚日志做数据,记录回滚日志的操做也会记录到重作日志中。这样回滚日志就能够像数据同样缓存起来,而不用在重写日志以前写入磁盘了。
一、内容:
逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务以前的状态,而不是从物理页面上操做实现的,这一点是不一样于redo log的。
二、何时产生?
事务开始以前,将当前是的版本生成undo log,undo 也会产生 redo 来保证undo log的可靠性
三、何时释放?
当事务提交以后,undo log并不能立马被删除,而是放入待清理的链表,由purge线程判断是否由其余事务在使用undo段中表的上一个事务以前的版本信息,决定是否能够清理undo log的日志空间。
一、做用:
用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。 用于数据库的基于时间点的还原。
二、内容:
逻辑格式的日志,能够简单认为就是执行过的事务中的sql语句。
但又不彻底是sql语句这么简单,而是包括了执行的sql语句(增删改)反向的信息,也就意味着delete对应着delete自己和其反向的insert;update对应着update执行先后的版本的信息;insert对应着delete和insert自己的信息。
在使用mysqlbinlog解析binlog以后一些都会真相大白。
所以能够基于binlog作到相似于oracle的闪回功能,其实都是依赖于binlog中的日志记录。
三、何时产生:
事务提交的时候,一次性将事务中的sql语句(一个事物可能对应多个sql语句)按照必定的格式记录到binlog中。这里与redo log很明显的差别就是redo log并不必定是在事务提交的时候刷新到磁盘,redo log是在事务开始以后就开始逐步写入磁盘。
所以对于事务的提交,即使是较大的事务,提交(commit)都是很快的,可是在开启了bin_log的状况下,对于较大事务的提交,可能会变得比较慢一些。这是由于binlog是在事务提交的时候一次性写入的形成的,这些能够经过测试验证。
四、何时释放:
binlog的默认是保持时间由参数expire_logs_days配置,也就是说对于非活动的日志文件,在生成时间超过expire_logs_days配置的天数以后,会被自动删除。
在MySQL数据库中还有一种二进制日志,其用来基于时间点的还原及主从复制。从表面上来看其和重作日志很是类似,都是记录了对于数据库操做的日志。可是,从本质上来看有着很是大的不一样。 首先重作日志是在InnoDB存储引擎层产生的,而二进制日志是在MySQL数据库的上层产生的。其次,两种日志记录的内容形式不一样。二进制日志是一种逻辑日志,其记录的是对应的SQL语句。而重作日志是物理日志,记录的是每一个页的修改。此外,两种日志记录写入磁盘的时间点不一样,二进制日志只在事务提交完成后进行一次写入,重作日志在事务进行时不断地写入。
事务就是一个操做序列,这些操做要么都执行,要么都不执行,它是一个不可分割的工做单位。事务是数据库维护数据一致性的单位,在每一个事务结束时,都能保持数据一致性。
原子性、一致性、隔离性、持久性 (ACID)
(隔离性由锁来实现;原子性、一致性和持久性经过数据库的redo和undo来完成。)
经过锁能够实现事务隔离性的要求,使得事务能够并发地工做。由于事务隔离性的要求,锁会带来3种问题:丢失更新、脏读、不可重复读。
丢失更新:
指一个事务正在访问修改数据,与此同时另外一个事务也在访问修改此数据,两个事务互相不知道对方的存在。假如在是事务A修改数据前事务B已经修改过1次数据,那么事务A最终只能查询到假数据,丢失了更新操做。
解决方案:
悲观锁的方式: 加锁,建议最后一步更新数据的时候加上排它锁,不要在一开始就加锁。执行到了最后一步更新,首先作一下加锁的查询确认数据有没有没改变,若是没有被改变,则进行数据的更新,不然失败。 必定要是作加锁的查询确认,由于若是你不加锁的话,有可能你在作确认的时候数据又发生了改变。
乐观锁的方式:使用版本控制实现。
脏读:
一个事务读取了另外一个事务未提交的数据,那这个读取就是脏读。
解决方法 : 把数据库的事务隔离级别调整到read commited。
不可重复读:
不可重复读是指在一个事务内屡次读同一数据,在这个事务尚未结束时,另一个事务也访问并修改该同一数据,那么在第一个事务的两次读数据之间,因为第二个事务的修改,第一个事务两次读到的数据多是不同的。这样就发生了在一个事务内两次读到的数据是不同的,所以称为不可重复读。
如何避免:InnoDB存储引擎中,经过使用Next-Key Lock算法来避免不可重复读的问题。在Next-Key Lock算法下,对于索引的扫描,不只仅是锁住扫描到的索引,并且还能锁住这些索引覆盖的范围。所以对于这个范围内的插入都是不容许的。InnoDB存储引擎的默认事务隔离级别是READ REPEATABLE,采用Next-Key Lock算法,就避免了不可重复读的现象。
解决办法:把数据库的事务隔离级别调整到 REPEATABLE READ , 读取时候不容许其余事务修改该数据,无论数据在事务过程当中读取多少次,数据都是一致的。
幻读:
是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的所有数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,之后就会发生操做第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉同样。
如何避免:Repeatable read及以上级别经过间隙锁来防止幻读的出现,即锁定特定数据的先后间隙让数据没法被插入。
InnoDB经过预写日志的方式来保证事务的完整性。这意味着磁盘上存储的数据页和内存缓冲池中的数据页是不一样步的,对于内存缓冲池中页的修改,先是写入重作日志文件,而后再写入磁盘,所以是一种异步的方式。
乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。
悲观锁:假定会发生并发冲突,屏蔽掉一切可能违反数据完整性的操做,在读取的时候就对数据进行加锁, 在该用户读取数据的期间,其余任何用户都不能来修改该数据,可是其余用户是能够读取该数据的, 只有当本身读取完毕才释放锁。
乐观锁:假定不会发生并发冲突,只在提交的时候检查是否发生并发冲突。
事务和锁的存在都是为了更好地解决并发访问形成的数据不一致性问题。乐观锁和悲观锁都是为了解决并发控制问题,乐观锁能够看作一种在最后提交时检测冲突的手段,而悲观锁是一种避免冲突的手段。
(1)乐观锁:假设不会发生并发冲突,只在提交的时候检查是否发生并发冲突。能够使用版本号机制和CAS算法实现。
版本号机制:通常在数据表中加一个数据版本号version字段,表示数据被修改的次数,当数据被修改时version值加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若当前读取到的version值与第一次读取到的数据库version值相等时才更新,不然重试更新操做,直到更新成功。
例子:
假设数据库中账户信息表中有一个 version 字段,当前值为 1 ;而当前账户余额字段( balance )为 100 。
- 操做员A此时将其读出( version=1 ),并从其账户余额中扣除 50(100-50 =50);
- 在操做员A操做的过程当中,操做员B也读入此用户信息( version=1 ),并从其账户余额中扣除20 (100-20=80 )。
- 操做员A完成了修改工做,将数据版本号加一( version=2 ),连同账户扣除后余额( balance=50 ),提交至数据库更新,此时因为提交数据版本大于数据库记录当前版本,数据被更新,数据库记录 version 更新为 2 ;
- 操做员B完成了操做,也将版本号加一( version=2 )试图向数据库提交数据( balance=80 ),但此时比对数据库记录版本时发现,操做员 B 提交的数据版本号为 2 ,数据库记录当前版本也为 2 ,不知足 “ 当前最后更新的version与操做员第一次的版本号相等 “ 的乐观锁策略,所以,操做员B的提交被驳回。
CAS机制:即compare and swap(比较与交换),无锁编程,在不使用锁的状况下实现多线程之间的变量同步,也就是在没有线程被阻塞的状况下实现变量的同步,所以也叫非阻塞同步。
CAS过程是这样:它包含3个参数:内存值V(要更新变量的值),旧的预期值A,要修改的值B。当且仅当预期值A的值等于内存值V时,才会将内存值V修改成B,不然不会执行任何操做(V值和A值不一样,则说明已经有其余线程作了更新)。通常状况下是一个自旋操做,即不断的重试。
例子:
- 假设 t1,t2 线程同时更新同一变量56的值。
- 由于t1和t2线程都同时去访问同一变量56,因此他们会把主内存的值彻底拷贝一份到本身的工做内存空间,因此t1和t2线程的预期值都为56。
- 假设t1在与t2线程竞争中线程t1能去更新变量的值,而其余线程都失败。(失败的线程并不会被挂起,而是被告知此次竞争中失败,并能够再次发起尝试)。t1线程去更新变量值改成57,而后写到内存中。此时对于t2来讲,内存值变为了57,与预期值56不一致,就操做失败了(想改的值再也不是原来的值)。
乐观锁的优点和劣势 :
优点:若是数据库记录始终处于悲观锁加锁状态,能够想见,若是面对几百上千个并发,那么要不断的加锁减锁,并且用户等待的时间会很是的长, 乐观锁机制避免了长事务中的数据库加锁解锁开销,大大提高了大并发量下的系统总体性能表现。因此若是系统的并发很是大的话,悲观锁定会带来很是大的性能问题,因此建议就要选择乐观锁定的方法, 而若是并发量不大,彻底能够使用悲观锁定的方法。乐观锁也适合于读比较多的场景。
劣势: 乐观锁只能在提交数据时才发现业务事务将要失败,若是系统的冲突很是的多,并且一旦冲突就要由于从新计算提交而形成较大的代价的话,乐观锁也会带来很大的问题。并且乐观锁也没法解决脏读的问题 。(2)悲观锁:假定会发生并发冲突,在读取的时候就对数据进行加锁, 在该用户读取数据的期间,其余任何用户都不能来修改该数据,可是其余用户是能够读取该数据的, 只有当本身读取完毕才释放锁。
在数据库中能够使用Repeatable Read的隔离级别(可重复读)来实现悲观锁,它彻底知足悲观锁的要求(加锁)。Java中
悲观锁的优点和劣势 :synchronized
和ReentrantLock
等独占锁就是悲观锁思想的实现。
优点: 能避免冲突的发生 。
劣势 :开销较大,并且加锁时间较长,对于并发的访问性支持很差。两种锁的使用场景:
若是冲突不多,或者冲突的后果不会很严重,那么一般状况下应该选择乐观锁,由于它能获得更好的并发性;
若是冲突太多或者冲突的结果对于用户来讲痛苦的,那么就须要使用悲观策略,它能避免冲突的发生。
通常乐观锁适用于写比较少的状况下(多读场景),即冲突真的不多发生的时候;悲观锁适用于多写的状况,多写的状况通常会常常产生冲突。
共享锁和排它锁是具体的锁,是数据库机制上的锁。
加锁会有粒度问题,从粒度上从大到小能够划分为 :
存储过程:
(1)定义:
存储过程是一组SQL命令集合,通过预编译存放在系统中。也就是将经常使用的或很复杂的工做,预先用SQL语句写好并用一个指定的名称存储起来,之后只要调用它就能够完成相应的功能。
(2)存储过程的种类:
存储过程通常分为“系统存储过程”与“用户存储过程”。系统存储过程通常以sp_开头,用户不能够编辑修改,只能调用;用户存储过程是用户编写的处理数据的存储过程。
(3)存储过程的建立和使用:
create procedure proc1 --建立一个存储过程
as begin
--在存储过程当中处理SQL
select * from bank
end
【注】若是有参数,存储过程的参数是在as关键字以前,as以后的是局部变量,2种变量在存储过程当中均可以使用,可是命名时不能够冲突。例:
create procedure proc2
@mobile varchar(50),@sendMsg varchar(50)
as
begin
print @mobile ---输出mobile这个参数
end
(4)存储过程与通常的SQL语句有什么区别呢? (存储过程的优势: )
缺点:对于简单的sql语句不必使用存储过程,存储过程适合用于对数据库进行复杂的操做。
触发器:
(1)定义:
触发器(Trigger)是个特殊的存储过程,它不是由用户主动发起调用的,而是当发生某一事件而触发,由系统自动调用。好比当用户在数据库中新增一条商品记录,咱们但愿同时在库存中作登记,而库存登记不是人工去录入,是在发生新增商品记录这一事件时发生,由系统自动完成录入,这个工做就能够交给一个特殊的存储过程来完成,这个存储过程就是触发器。
(2)触发器的工做机制:
触发器是建在表上的,当这个表发生新增、修改、删除操做时,若是这个表上有触发器,就会被自动调用。在这个事件的过程当中,系统会产生一个临时表,这个临时表只有一行记录:
当须要触发器连带操做登记库存时就能够从inserted表或者deleted表中得到变量,更新到库存表中数据。
(3)做用:维护表的完整性,记录表的修改来审计表的相关信息。分为:
触发器用处仍是不少的,好比校内网、开心网、Facebook,你发一个日志,自动通知好友,其实就是在增长日志时作一个后触发,再向通知表中写入条目。由于触发器效率高。
(4)建立触发器的SQL语法:
create trigger 触发器名称 --触发器名称
on 表名 --建在那个表上
for insert|update|delete --是插入事件处理仍是修改事件处理仍是删除事件处理
as --如下是触发器基本格式
begin
end
调用存储过程:call procedure_name(参数,参数...)
(5)触发器优势:
缺点:不一样数据库,语法差异很大,移植困难,换了数据库,须要从新编写;很差管理,把过多业务逻辑写在存储过程很差维护,不利于分层管理,容易混乱,通常存储过程适用于个别对性能要求较高的业务。
存储过程与触发器:
它们都是sql语句集,不一样的是:
存储过程是须要用户调用的(经过存储过程名字直接调用),而触发器不是由用户主动发起调用的,而是当发生某一事件而触发,由系统自动调用。在insert、delete和update命令以前或以后自动调用sql命令或者存储过程。
函数:
函数:MySQL中提供了许多内置函数,还能够自定义函数(实现程序员须要sql逻辑处理)
自定义函数建立语法:
建立:CREATE FUNCTION 函数名称(参数列表)
RETURNS 返回值类型 函数体
修改: ALTER FUNCTION 函数名称 [characteristic ...]
删除:DROP FUNCTION [IF EXISTS] 函数名称
调用:SELECT 函数名称(参数列表)
存储过程和函数的区别:
索引是对数据库表中一或多个列的值进行排序的结构,利用索引可快速访问数据库表的特定信息。
举个例子:假设有一张数据表Emplyee,该表有三列:Employee_name,Employee_age,Employee_address,表中有几万条记录。如今要执行下面这条查询语句:Select * from Employee where Employee_name='Jesus'。
若是没有数据库索引功能,数据库系统会全表扫描,逐行的遍历整张表,对于每一行都要检查其Employee_Name字段是否等于“Jesus”。而数据库索引功能索引的最大做用就是加快查询速度,它能从根本上减小须要扫表的记录/行的数量。
优势:
缺点:
普通索引、惟一索引、主键索引、联合索引、全文索引。
http://www.javashuo.com/article/p-kijtdxkb-k.html
一般,经过索引查询数据比全表扫描要快。可是咱们也必须注意到它的代价:
索引须要空间来存储,也须要按期维护,每当有记录在表中增减或索引列被修改时,索引自己也会被修改。这意味着每条记录的INSERT、DELETE、UPDATE将为此多付出4,5 次的磁盘I/O。由于索引须要额外的存储空间和处理,那些没必要要的索引反而会使查询反应时间变慢。使用索引查询不必定能提升查询性能,索引范围查询(INDEX RANGE SCAN)适用于两种状况:
联合索引是指对表上的多个列作索引。在mysql创建联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配。
最左前缀匹配原则:
最左优先,在检索数据时从联合索引的最左边开始匹配。
对列col一、列col2和列col3建一个联合索引:
KEY test_col1_col2_col3 on test(col1,col2,col3);
联合索引 test_col1_col2_col3 至关于创建了(col1)、(col1,col2)、(col,col2,col3)三个索引。
(1)
SELECT * FROM test WHERE col1="1" AND clo2="2" AND clo4=|"4"
上面这个查询语句执行时会依照最左前缀匹配原则,检索时会使用索引(col1,col2)进行数据匹配。
(2)索引的字段能够是任意顺序的,如:
SELECT * FROM test WHERE col1=“1” AND clo2=“2” SELECT * FROM test WHERE col2=“2” AND clo1=“1”
这两个查询语句都会用到索引(col1,col2),mysql建立联合索引的规则是首先会对联合合索引的最左边的,也就是第一个字段col1的数据进行排序,在第一个字段的排序基础上,而后再对后面第二个字段col2进行排序。其实就至关于实现了相似 order by col1 col2这样一种排序规则。
有人会疑惑第二个查询语句不符合最左前缀匹配:首先能够确定是两个查询语句都保函索引(col1,col2)中的col一、col2两个字段,只是顺序不同,查询条件同样,最后所查询的结果确定是同样的。既然结果是同样的,到底以何种顺序的查询方式最好呢?此时咱们能够借助mysql查询优化器explain,explain会纠正sql语句该以什么样的顺序执行效率最高,最后才生成真正的执行计划。
(3)若是只查询col2:
SELECT * FROM test WHERE col2=2;
第一个col字段是绝对有序的,而第二字段就是无序的了。因此一般状况下,直接使用第二个字段col2进行条件判断是用不到索引的。固然是col2字段的索引数据也是有序的状况下才能使用咯,何时才是有序的呢?在col1字段是等值匹配的状况下,cid才是有序的。这也就是mysql索引规则中要求复合索引要想使用第二个索引,必须先使用第一个索引的缘由。(并且第一个索引必须是等值匹配)。
为何要使用联合索引?
- 减小开销。建一个联合索引(col1,col2,col3),实际至关于建了(col1),(col1,col2),(col1,col2,col3)三个索引。每多一个索引,都会增长写操做的开销和磁盘空间的开销。对于大量数据的表,使用联合索引会大大的减小开销!
- 覆盖索引。对联合索引(col1,col2,col3),若是有以下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那么MySQL能够直接经过遍历索引取得数据,而无需回表,这减小了不少的随机io操做。减小io操做,特别的随机io实际上是dba主要的优化策略。因此,在真正的实际应用中,覆盖索引是主要的提高性能的优化手段之一。
- 效率高。索引列越多,经过索引筛选出的数据越少。有1000W条数据的表,有以下sql:select from table where col1=1 and col2=2 and col3=3,假设假设每一个条件能够筛选出10%的数据,若是只有单值索引,那么经过该索引能筛选出1000W10%=100w条数据,而后再回表从100w条数据中找到符合col2=2 and col3= 3的数据,而后再排序,再分页;若是是联合索引,经过索引筛选出1000w10% 10% *10%=1w,效率提高可想而知!
从本质上来讲,联合索引仍是一颗B+树,不一样的是联合索引的键值的数量不是1,而是大于等于2。
对于查询 SELECT * FROM TABLE WHERE a=xxx and b=xxx,显然能够使用(a,b)这个联合索引。对于单个的a列查询 SELECT * FROM TABLE WHERE a=xxx 也是能够使用(a,b)索引。但对于b列的查询 SELECT * FROM TABLE WHERE b=xxx 不能够使用这颗B+树索引。由于叶节点上的b值为1,2,1,4,1,2,显然不是排序的,所以对于b列的查询使用不到(a,b)的索引。
联合索引的第二个好处是,能够对第二个键值进行排序。例如,在不少状况下咱们都须要查询某个用户的购物状况,并按照时间排序,去除最近3次的购买记录,这是使用联合索引能够避免多一次的排序操做,由于索引自己在叶节点已经排序了。
【注】:对于相同的第一个键值的数据,第二个键值是排好序的。
对于单个列a的查询每每使用单个键的索引,由于其叶节点包含单个键值,能存放的记录更多。
Hash索引和B+树索引的特色:
Hash索引结构的特殊性,其检索效率很是高,索引的检索能够一次定位;
B+树索引须要从根节点到枝节点,最后才能访问到页节点这样屡次的IO访问。
Hash索引与B+树索引区别?
B+树是一种平衡查找树。在B+树中,全部记录节点都是按键值的大小顺序存放在同一层的叶节点中,各叶结点指针进行链接。
(平衡二叉树AVL:首先符合二叉查找树的定义(最结点的值比根节点小,右结点的值比根结点大),其次必须知足任何节点的左右两个子树的高度最大差为1。)
(1)B+的磁盘读写代价更低
B+的内部结点并无指向关键字具体信息的指针。所以其内部结点相对B树更小。若是把全部同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的须要查找的关键字也就越多。相对来讲IO读写次数也就下降了。
(2)B+tree的查询效率更加稳定
因为非终结点并非最终指向文件内容的结点,而只是叶子结点中关键字的索引。因此任何关键字的查找必须走一条从根结点到叶子结点的路。全部关键字查询的路径长度相同,致使每个数据的查询效率至关。
数据库中的B+索引能够分为汇集索引和辅助汇集索引。无论是汇集索引仍是非汇集的索引,其内部都是B+树的,即高度平衡的,叶节点存放着全部的数据,汇集索引与非汇集索引不一样的是,叶节点存放的是不是一整行的信息。
汇集索引就是按照每张表的主键构造一颗B+树,而且叶节点中存放着整张表的行记录数据,所以也让汇集索引的叶节点成为数据页。汇集索引的这个特性决定了索引组织表中数据也是索引的一部分。因为实际的数据页只能按照一颗B+树进行排序,所以每张表只能拥有一个汇集索引。
汇集索引表记录的排列顺序和索引的排列顺序一致,因此查询效率快,只要找到第一个索引值记录,其他就连续性的记录在物理也同样连续存放。汇集索引对应的缺点就是修改慢,由于为了保证表中记录的物理和索引顺序一致,在记录插入的时候,会对数据页从新排序。
对于辅助索引(非汇集索引),叶级别不包含行的所有数据。汇集索引键来告诉InnoDB存储引擎,哪里能够找到与索引相对应的行数据。辅助索引的存在并不影响数据在汇集索引中的组织,所以每张表上能够有多个辅助索引。经过辅助索引来寻找数据时,InnoDB存储引擎会遍历辅助索引并经过叶级别的指针得到指向主键索引的主键,而后再经过主键索引来找到一个完整的行记录。
非汇集索引指定了表中记录的逻辑顺序,可是记录的物理和索引不必定一致,两种索引都采用B+树结构,非汇集索引的叶子层并不和实际数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中的指针方式。非汇集索引层次多,不会形成数据重排。
根本区别:
汇集索引和非汇集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致。
(1)truncate和delete只删除数据,而drop则删除整个表(结构和数据)。
(2)delete语句执行删除的过程是每次从表中删除一行,而且同时将该行的删除操做做为事务记录在日志中保存以便进行进行回滚操做。truncate table则一次性地从表中删除全部的数据并不把单独的删除操做记录记入日志保存,删除行是不能恢复的。而且在删除的过程当中不会激活与表有关的删除触发器。执行速度快。
(3)执行速度:drop> truncate >delete
(4)delete语句是dml,这个操做会放到rollback segement中,事务提交以后才生效。若是有相应的trigger(触发器),执行的时候将被触发;
truncate、drop是ddl,操做当即生效,原数据不放到rollback segment中,不能回滚,操做不触发trigger。
(5)当表被truncate后,这个表和索引所占用的空间会恢复到初始大小, delete操做不会减小表或索引所占用的空间。
(5)应用范围:truncate只能对table;delete能够是table和view
若是直接删除一个表drop,对数据量很大的表,这个过程会占用比较长的时间,若是先truncat后drop table:一、能够下降操做失败的风险;二、能够下降数据字典锁占用的时间,下降系统开销。
超键 :在关系中能惟一标识元组的属性集称为关系模式的超键。一个属性能够为做为一个超键,多个属性组合在一块儿也能够做为一个超键。超键包含候选键和主键。
候选键:是最小超键,即没有冗余元素的超键。
主键 :数据库表中对存储数据对象予以惟一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。
外键 :在一个表中存在的另外一个表的主键称此表的外键。
若是咱们定义了主键(PRIMARY KEY),那么InnoDB会选择主键做为汇集索引、若是没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的惟一索引做为主键索引、若是也没有这样的惟一索引,则InnoDB会选择内置6字节长的ROWID做为隐含的汇集索引(ROWID随着行记录的写入而主键递增,这个ROWID不像ORACLE的ROWID那样可引用,是隐含的)。
char是一种固定长度的类型,varchar是一种可变长度的类型。
varchar(50)中50的含义:
最多存放50个字符,varchar(50)和(200)存储hello所占空间同样,但后者在排序时会消耗更多内存,由于order by col采用fixed_length计算col长度。ppp-
int(20)中20的含义:
是指显示字符的长度
但要加参数的,最大为255,好比它是记录行数的id,插入10笔资料,它就显示00000000001 ~~~00000000010,当字符的位数超过11,它也只显示11位,若是你没有加那个让它未满11位就前面加0的参数,它不会在前面加0.
20表示最大显示宽度为20,但仍占4字节存储,存储范围不变;
mysql为何这么设计:
对大多数应用没有意义,只是规定一些工具用来显示字符的个数;int(1)和int(20)存储和计算均同样。
视图(View)是一个命名的虚表,它由一个查询来定义,能够看成表使用。
视图有什么用(应用场景):
一、当一个查询你须要频频的做为子查询使用时,视图能够简化代码,直接调用而不是每次都去重复写这个东西。
二、系统的数据库管理员,须要给他人提供一张表的某两列数据,而不但愿他能够看到其余任何数据,这时能够建一个只有这两列数据的视图,而后把视图公布给他。
建立视图sql语句:
CREATE VIEW view_name AS
SELECT column_name(s)
FROM table_name
WHERE condition
视图与表的区别:
一、视图是已经编译好的sql语句,而表不是。
二、视图没有实际的物理记录,而表有。
三、表是内容,视图是窗口。
四、表只用物理空间而视图不占用物理空间,视图只是逻辑概念的存在,表能够及时对它进行修改,但视图只能由建立的语句来修改。
五、视图是查看数据表的一种方法,能够查询数据表中某些字段构成的数据,只是一些SQL语句的集合。从安全的角度说,视图能够不给用户接触数据表,从而不知道表结构。
六、表属于全局模式中的表,是实表;视图属于局部模式的表,是虚表。
七、视图的创建和删除只影响视图自己,不影响对应的基本表。
八、不能对视图进行update或者insert into操做。
第一范式(1NF)
(在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不知足第一范式(1NF)的数据库就不是关系数据库。)
所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,第一范式就是无重复的列。强调的是列的原子性,即列不可以再分红其余几列。
第二范式(2NF)
知足第二范式(2NF)必须先知足第一范式(1NF)。另外包含两部份内容,一是表必须有主键;二是没有包含在主键中的列必须彻底依赖于主键,而不能只依赖于主键的一部分。
第三范式(3NF)
知足第三范式(3NF)必须先知足第二范式(2NF)第三范式就是属性不依赖于其它非主属性。非主键列必须直接依赖于主键,不能存在传递依赖。
1. explain sql 分析sql语句,这个语句能够打印出的各类item的意义:
2. 查询语句不一样元素(where、jion、limit、group by、having等等)执行前后顺序?
查询中用到的关键词主要包含6个,而且他们的顺序依次为 select--from--where--group by--having--order by--limit。
其中select和from是必须的,其余关键词是可选的。
(使用having字句对分组后的结果进行筛选,因此having只能用在group by以后;
limit 起始记录位置:取记录的条数对记录进行选取,主要用来实现分页功能)
非关系型数据库的优点:
关系型数据库的优点:
其余:
1.对于这两类数据库,对方的优点就是本身的弱势,反之亦然。
2.NOSQL数据库慢慢开始具有SQL数据库的一些复杂查询功能,好比MongoDB。
3.对于事务的支持也能够用一些系统级的原子操做来实现例如乐观锁之类的方法来曲线救国,好比Redis set nx。
例如1:
SELECT a.,b. FROM luntan LEFT JOIN usertable as b ON a.username=b.username
例如2:
SELECT a.,b. FROM city as a FULL OUTER JOIN user as b ON a.username=b.username
例如:
SELECT type,pub_name FROM titles CROSS JOIN publishers ORDER BY type
1.以A,B两张表为例
A left join B
选出A的全部记录,B表中没有的以null 代替
right join 同理
2.inner join
A,B的全部记录都选出,没有的记录以null代替
3.cross join (笛卡尔积)
A中的每一条记录和B中的每一条记录生成一条记录
例如A中有4条,B中有4条,cross join 就有16条记录
% 通配符
:表示任何字符出现任意次数 (能够是0次)。 _ 通配符
:表示只能匹配单个字符,不能多也不能少,就是一个字符。
使用通配符进行模糊查询须要用 like操做符,例:
SELECT * FROM products WHERE products.prod_name like '%es%';
SELECT * FROM products WHERE products.prod_name like '_es';
【注】若是在使用like操做符时,后面的没有使用通用匹配符效果是和 = 是
一致的。
SELECT * FROM products WHERE products.prod_name like '1000':
只能匹配的结果为1000
,而不能匹配像JetPack 1000
这样的结果。
count(column) :对特定的列的值具备的行进行计数,不包含NULL值。
count(1)这个用法和count(*)的结果是同样的,包含null。
性能问题:
count(1)跟count(主键)同样,只扫描主键;count(*)跟count(非主键)同样,扫描整个表。明显前者更快一些。
若是是utf8字符集的话,须要升级至utf8_mb4方可支持。
监控的工具备不少,例如zabbix,lepus,我这里用的是lepus。
开启慢日志查询:set global slow_query_log='ON';
那么开启了慢查询日志后,什么样的SQL才会记录到慢查询日志里面呢?
这个是由参数long_query_time控制,默认状况下long_query_time的值为10秒,能够使用命令修改,也能够在my.cnf参数里面修改。运行时间大于long_query_time(非大于等于),才会记录到慢查询日志里。
MongoDB是神马?
MongoDB是非关系型数据库,是一个基于分布式文件存储的数据库。(文档型数据库:能够存放xml、json、bson类型的数据。)同时MongoDB是由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 是非关系数据库当中功能最丰富,最像关系数据库的。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档相似于 JSON 对象。字段值能够包含其余文档,数组及文档数组。
它能够存储比较复杂的数据类型。Mongo最大的特色是它支持的查询语言很是强大,其语法有点相似于面向对象的查询语言,几乎能够实现相似关系数据库单表查询的绝大部分功能,并且还支持对数据创建索引。
mongodb与mysql不一样,mysql的每一次更新操做都会直接写入硬盘,可是mongo不会,做为内存型数据库,数据操做会先写入内存,而后再会持久化到硬盘中去 ,但MongoDB采用的预分配空间的方式来防止文件碎片,因此MongoDB的数据文件很大。
MongoDB的特色是:
(1)面向文档(2)高性能(3)高可用(4)易扩展(5)丰富的查询语言
MongoDB 缺点:
① MongoDB 不支持事务操做(最主要的缺点)
② MongoDB 占用空间过大
③ MongoDB 没有如 MySQL 那样成熟的维护工具,这对于开发和IT运营都是个值得注意的地方
存储方式:虚拟内存+持久化。
持久化方式:MongoDB 的全部数据其实是存放在硬盘的,全部要操做的数据经过 mmap 的方式映射到内存某个区域内。而后,MongoDB 就在这块区域里面进行数据修改,避免了零碎的硬盘操做。
mongodb,mysql的区别?
(1)MongoDB 非关系型数据库,MySql是关系型数据库
(2)MongoDB存储方式:虚拟内存+持久化; MySql在不一样的引擎上有不一样 的存储方式。
(3)MongoDB查询语句:是独特的Mongodb的查询方式; MySqlMySql查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。
(4)mysql的每一次更新操做都会直接写入硬盘,可是mongo的数据操做会先写入内存,而后再会持久化到硬盘中去 。(MongoDB数据是存储在硬盘上的,只不过须要常常读取的数据会被加载到内存中,将数据存储在物理内存中,从而达到高速读写。)
(5)mysql缺点就是在海量数据处理的时候效率会显著变慢。在适量级的内存的Mongodb的性能是很是迅速的。
(6)MongoDB 不支持事务操做,mysql的innodb和bdb存储引擎支持事务。(注:myisam不支持事务)
先简单介绍一下一些组件的基本做用:
一条查询语句的执行顺序:
1.客户端经过TCP链接发送链接请求到mysql链接器,链接器会对该请求进行权限验证及链接资源分配。
2.创建链接后客户端发送一条语句,mysql收到该语句后,经过命令分发器判断其是不是一条select语句,若是是,在开启查询缓存的状况下,先在查询缓存中查找该SQL是否彻底匹配,若是彻底匹配,验证当前用户是否具有查询权限,若是权限验证经过,直接返回结果集给客户端,该查询也就完成了。若是不匹配继续向下执行。
3.若是在查询缓存中未匹配成功,则将语句交给分析器做语法分析,MySQL须要知道到底要查哪些东西,若是语法不对,就会返回语法错误中断查询。
4.分析器的工做完成后,将语句传递给预处理器,检查数据表和数据列是否存在,解析别名看是否存在歧义等
5.语句解析完成后,MySQL就知道要查什么了,以后会将语句传递给优化器进行优化(经过索引选择最快的查找方式),并生成执行计划。
6.以后交给执行器去具体执行该语句,在执行以前,会先检查该用户是否具备查询权限,若是有,继续执行该语句。执行器开始执行后,会逐渐将数据保存到结果集中,同时会逐步将数据缓存到查询缓存中,最终将结果集返回给客户端。(若是该SQL执行过程当中超过了慢查询阀值,该SQL会被记录到慢查询日志中)
一条更新语句的执行顺序:
。。。。。
有一条记录须要更新的时候,InnoDB引擎就会先把记录写到 redo log(粉板)里,并更新到内存,这个时候更新就算完成了,同时,InnoDB引擎会在适合的时候,将这个操做记录更新到磁盘里面,而这个更新每每实在系统比较空闲的时候作。