目录
数据库三大范式是什么
MyISAM索引与InnoDB索引的区别
InnoDB引擎的4大特性
存储引擎选择
什么是索引
索引的优缺点
索引覆盖
索引有哪几种类型
创建索引的原则(重中之重)
创建索引
删除索引
百万级别或者以上的数据如何删除
B树和B+树的区别
什么是聚簇索引
什么是数据库事务
事务的四大特性(ACID)
什么是脏读、幻读、不可重复读
事务的四个隔离级别
按照锁的粒度分数据库锁有哪些
从锁的类别上分数据库锁有哪些
什么是死锁?怎么解决
乐观锁和悲观锁是什么
视图有哪些特点?
什么是游标?
SQL语句主要分为哪几类
六种关联查询
UNION与UNION ALL的区别?
varchar与char的区别
SQL的生命周期?
大表数据查询,怎么优化
超大分页怎么处理?
大表怎么优化?某个表有近千万数据,CRUD比较慢,如何优化?分库分表了是怎么做的?分表分库了有什么问题?有用到中间件么?他们的原理知道么?
MySQL的复制原理以及流程
第一范式:每个列都不可以再拆分。
第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是只依赖于主键的一部分。
第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。
在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由。比如性能。
InnoDB索引是聚簇索引,MyISAM索引是非聚簇索引。
InnoDB的主键索引的叶子结点存储着行数据,因此主键索引非常高效。
MyISAM索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据。
InnoDB非主键索引的叶子结点存储的是主键和其他带索引的列数据,因此查询时做到覆盖索引会非常有效。
插入缓冲(insert buffer)
二次写(double write)
自适应哈希索引(ahi)
预读(read ahead)
如果没有特别的需求,使用默认的InnoDB即可。
MyISAM:以读写插入为主的应用程序,比如博客系统、新闻门户网站。
InnoDB:更新(删除)操作频率也高,或者要保证数据的完整性;并发量高,支持事务和外键。比如OA自动化办公系统。
索引是一种特殊的文件,他们包含着对数据表里所有记录的引用指针。
索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树
优点:
可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
缺点:
时间方面:创建索引和维护索引要耗费时间。
空间方面:索引需要占物理空间。
如果要查询的字段都建立过索引,那么引擎会直接在索引表中查询而不会访问原数据(否则只要有一个字段没有简历索引就会缩权标扫描),这叫索引覆盖。
主键索引:数据列不允许重复,不允许为NULL,一个表只能有一个主键。
唯一索引:数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。
ALTER TABLE table_name ADD UNIQUE (column); 创建唯一索引
ALTER TABLE table_name ADD UNIQUE (column1,column2); 创建唯一组合索引
普通索引:基本的索引类型,没有唯一性限制,允许为NULL值
ALTER TABLE table_name ADD INDEX index_name (column);创建普通索引
ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);创建组合索引
全文索引:是目前搜索引擎使用的一种关键技术。
ALTER TABLE table_name ADD FULLTEXT (column);创建全文索引
索引虽好,但也不是无限制的使用,最好符合一下几个原则
1) 最左前缀匹配原则,组合索引非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
2)较频繁作为查询条件的字段才去创建索引
3)更新频繁字段不适合创建索引
4)若是不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低)
5)尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
6)定义有外键的数据列一定要建立索引。
7)对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。
8)对于定义为text、image和bit的数据类型的列不要建立索引。
第一种:在执行create table时创建索引
CREATE TABLE user_index2 (
id INT auto_increment PRIMARY KEY,
first_name VARCHAR (16),
last_name VARCHAR (16),
id_card VARCHAR (18),
information text,
KEY name (first_name, last_name),
FULLTEXT KEY (information),
UNIQUE KEY (id_card)
);
第二种:使用alter table命令去增加索引
ALTER TABLE table_name ADD INDEX index_name (column_list);
第三种:使用alter table命令去增加索引
CREATE INDEX index_name ON table_name (column_list);
根据索引名删除普通索引、唯一索引、全文索引:alter table 表名 drop KEY 索引名
删除主键索引:alter table 表名 drop primary key
(因为主键只有一个)。这里值得注意的是,如果主键自增长,那么不能直接执行此操作(自增长依赖于主键索引),需要取消自增长再行删除。
关于索引:由于索引需要额外的维护成本,因为索引文件是单独存在的文件,所以当我们对数据的增加,修改,删除,都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增/改/删的执行效率。所以,在我们删除数据库百万级别数据的时候,查询MySQL官方手册得知删除数据的速度和创建的索引数量是成正比的。
事务是一个不可分割的数据库序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。
原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用。
一致性:执行事务前后,数据保持一致性,多个事务对同一个数据的读取的结果是相同的。
隔离性:并发访问数据库时,一个用户的事务不被其他的事务所干扰,个并发事务之间数据库是独立的。
持久性:一个数据被提交之后。它对数据库中数据的改变是持久的,及时数据库发生故障也不应该对其有影响。
脏读(dirty read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个rollback了操作,则后一个事务所读取的数据是脏数据。
幻读(phantom read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
不可重复读(non-repeatable read):在一个事务的两次查询之中,数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
这里需要注意的是:Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别
在关系型数据库中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。
MyISAM和InnoDB存储引擎使用的锁:
共享锁: 又叫做读锁。 当用户要进行数据的读取时,对数据加上共享锁。共享锁可以同时加上多个。
排他锁: 又叫做写锁。 当用户要进行数据的写入时,对数据加上排他锁。排他锁只可以加一个,他和其他的排他锁,共享锁都相斥。
死锁是指两个或多个事务在同一资源上互相占用,并请求锁定对方的资源,从而导致恶性循环的现象。
常见的解决死锁的方法:
1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。
2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;
数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。实现方式:乐一般会使用版本号机制或CAS算法实现。
两种锁的使用场景
从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。
但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。
视图的特点如下:
视图的列可以来自不同的表,是表的抽象和在逻辑意义上建立的新关系。
视图是由基本表(实表)产生的表(虚表)。
视图的建立和删除不影响基本表。
对视图内容的更新(添加,删除和修改)直接影响基本表。
当视图来自多个基本表时,不允许添加和删除数据。
视图的操作包括创建视图,查看视图,删除视图和修改视图。
游标是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果,每个游标区都有一个名字。用户可以通过游标逐一获取记录并赋给主变量,交由主语言进一步处理。
数据定义语言DDL(Data Ddefinition Language)CREATE,DROP,ALTER
主要为以上操作 即对逻辑结构等有操作的,其中包括表结构,视图和索引。
数据查询语言DQL(Data Query Language)SELECT
这个较为好理解 即查询操作,以select关键字。各种简单查询,连接查询等 都属于DQL。
数据操纵语言DML(Data Manipulation Language)INSERT,UPDATE,DELETE
主要为以上操作 即对数据进行操作的,对应上面所说的查询操作 DQL与DML共同构建了多数初级程序员常用的增删改查操作。而查询是较为特殊的一种 被划分到DQL中。
数据控制功能DCL(Data Control Language)GRANT,REVOKE,COMMIT,ROLLBACK
主要为以上操作 即对数据库安全性完整性等有操作的,可以简单的理解为权限控制等。
char的特点
char表示定长字符串,长度是固定的;
如果插入数据的长度小于char的固定长度时,则用空格填充;
因为长度固定,所以存取速度要比varchar快很多,甚至能快50%,但正因为其长度固定,所以会占据多余的空间,是空间换时间的做法;
对于char来说,最多能存放的字符个数为255,和编码无关
varchar的特点
varchar表示可变长字符串,长度是可变的;
插入的数据是多长,就按照多长来存储;
varchar在存取方面与char相反,它存取慢,因为长度不固定,但正因如此,不占据多余的空间,是时间换空间的做法;
对于varchar来说,最多能存放的字符个数为65532
总之,结合性能角度(char更快)和节省磁盘空间角度(varchar更小),具体情况还需具体来设计数据库才是妥当的做法。
应用服务器与数据库服务器建立一个连接
数据库进程拿到请求sql
解析并生成执行计划,执行
读取数据到内存并进行逻辑处理
通过步骤一的连接,发送结果到客户端
关掉连接,释放资源
超大的分页一般从两个方向上来解决.
select * from table where age > 20 limit 1000000,10
这种查询其实也是有可以优化的余地的. 这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢. 当时我们可以修改为select * from table where id in (select id from table where age > 20 limit 1000000,10)
.这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快. 同时如果ID连续的好,我们还可以select * from table where id > 1000000 limit 10
,效率也是不错的,优化的可能性有许多种,但是核心思想都一样,就是减少load的数据.解决超大分页,其实主要是靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中,直接返回即可.
当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:
还有就是通过分库分表的方式进行优化,主要有垂直分表和水平分表
垂直分区:
根据数据库里面数据表的相关性进行拆分。 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。
简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。 如下图所示,这样来说大家应该就更容易理解了。
垂直拆分的优点: 可以使得行数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;
垂直分表
把主键和一些列放在一个表,然后把主键和另外的列放在另一个表中
适用场景
缺点
水平分区:
保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。
水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。
水品拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 水平拆分最好分库 。
水平拆分能够 支持非常大的数据量存储,应用端改造也少,但 分片事务难以解决 ,跨界点Join性能较差,逻辑复杂。
《Java工程师修炼之道》的作者推荐 尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度 ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。
水平分表:
表很大,分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询次数
适用场景
水平切分的缺点
下面补充一下数据库分片的两种常见方案:
分库分表后面临的问题
事务支持 分库分表后,就成了分布式事务了。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价; 如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。
跨库join
只要是进行切分,跨节点Join的问题是不可避免的。但是良好的设计和切分却可以减少此类情况的发生。解决这一问题的普遍做法是分两次查询实现。在第一次查询的结果集中找出关联数据的id,根据这些id发起第二次请求得到关联数据。 分库分表方案产品
跨节点的count,order by,group by以及聚合函数问题 这些是一类问题,因为它们都需要基于全部数据集合进行计算。多数的代理都不会自动处理合并工作。解决方案:与解决跨节点join问题的类似,分别在各个节点上得到结果后在应用程序端进行合并。和join不同的是每个结点的查询可以并行执行,因此很多时候它的速度要比单一大表快很多。但如果结果集很大,对应用程序内存的消耗是一个问题。
数据迁移,容量规划,扩容等问题 来自淘宝综合业务平台团队,它利用对2的倍数取余具有向前兼容的特性(如对4取余得1的数对2取余也是1)来分配数据,避免了行级别的数据迁移,但是依然需要进行表级别的迁移,同时对扩容规模和分表数量都有限制。总得来说,这些方案都不是十分的理想,多多少少都存在一些缺点,这也从一个侧面反映出了Sharding扩容的难度。
ID问题
一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键生成机制。一方面,某个分区数据库自生成的ID无法保证在全局上是唯一的;另一方面,应用程序在插入数据之前需要先获得ID,以便进行SQL路由. 一些常见的主键生成策略
UUID 使用UUID作主键是最简单的方案,但是缺点也是非常明显的。由于UUID非常的长,除占用大量存储空间外,最主要的问题是在索引上,在建立索引和基于索引进行查询时都存在性能问题。 Twitter的分布式自增ID算法Snowflake 在分布式系统中,需要生成全局UID的场合还是比较多的,twitter的snowflake解决了这种需求,实现也还是很简单的,除去配置信息,核心代码就是毫秒级时间41位 机器ID 10位 毫秒内序列12位。
跨分片的排序分页
般来讲,分页时需要按照指定字段进行排序。当排序字段就是分片字段的时候,我们通过分片规则可以比较容易定位到指定的分片,而当排序字段非分片字段的时候,情况就会变得比较复杂了。为了最终结果的准确性,我们需要在不同的分片节点中将数据进行排序并返回,并将不同分片返回的结果集进行汇总和再次排序,最后再返回给用户。如下图所示:
主从复制:将主数据库中的DDL和DML操作通过二进制日志(BINLOG)传输到从数据库上,然后将这些日志重新执行(重做);从而使得从数据库的数据与主数据库保持一致。
主从复制的作用
MySQL主从复制解决的问题
MySQL主从复制工作原理
基本原理流程,3个线程以及之间的关联
主:binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中;
从:io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进自己的relay log中;
从:sql执行线程——执行relay log中的语句;
1.什么是数据库?
数据库是多个特俗文件的集合,是用来存储数据的,可高性能的存储数据和管理数据
2.数据库管理系统:
1.数据库文件 :用于存储数据
2.数据库管理系统服务端:用于管理数据库的文件
3.数据库管理系统的客户端:用于与服务端通信的
3.mysql服务器的主要配置选项有哪些?
bind-address表示服务器绑定的ip,默认为127.0.0.1
port表示端口,默认为3306
datadir表示数据库目录,默认为/var/lib/mysql
general_log_file表示普通日志,默认为/var/log/mysql/mysql.log
log_error表示错误日志,默认为/var/log/mysql/error.log
4.数据库的分类
1.关系型数据库:由多个表组成,表内部有一定关系,表与表之间有一定的联系
2.非关系型数据库
5.关系型数据库有哪些:
-oracle:电信,银行等大型项目
-ms sql server :微软生态圈的项目
-mysql:web时代最广泛的数据库
...
6.关系型数据库的核心元素
1.数据行(记录)
2.数据列(字段)
3.数据表(数据行的集合)
4.数据库(数据表的集合)
7.SQL(Structured Query Language)
SQL:结构化查询语言,是一种用来操作RDBMS的数据库语言
-dql:数据查询语言:通过sql查询数据
-dml:数据库操作语言:通过sql增删改 操作
-ddl:数据定义语言:通过sql对数据库,数据表的管理比如创建表等
提示: sql语句不区分大小写,每条sql语句后面加;
8.数据完整性:
1.数据库中存储的数据应该符合我们的预期,这就是的完整性
通过定义数据类型和数据约束两方面可实现数据的完整性
2.数据类型:
使用数据类型的原则是够用就行,尽量用取值范围比较小的,节省储存空间
-int:整数类型 unsigned:表示没有正负数之说
-dicemal:浮点数 dicmal(5,2)表示位数总共有5位,小数占两位
-varchar,char: varchar(3),当存储ab两个字符时就只占两位"ab",char(3)当存储ab两个字符时就占两位后还填充了一个空格“ab ”
-datatime :时间日期型
-enum:枚举类型
3.数据约束
主键(primary key)
非空(not null)
默认值(default)
唯一值(unique)
外键(foreign key):表示当前的某个字段是另一个表的主键,这个字段的值来自另一个标的主键