深度解析SQL和NoSQL数据库,掌握主流数据库【两万字解析】
大家好,我是辣条。
大家国庆玩的快乐否,玩开心的兄弟萌评论扣1,觉得不怎么样的兄弟萌扣2,我希望看到大家都是扣1呦,觉得这篇文章对你有帮助的话可以给辣条一个三连呦。
目录
数据库高级特性
存储引擎就是如何存储数据、如何为数据建立索引和如何更新、查询数据等技术的实现方法。
MySQL 默认支持多种存储引擎,以适用于不同领域 的数据库应用需要,用户可以通过选择使用不同的存储引擎提高应用的效率,提供灵活的存储。
-
InnoDB
事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键,InnoDB是默认的MySQL引擎。
InnoDB主要特性有:
- InnoDB 给 MySQL 提供了具有提交、回滚、崩溃恢复能力的事务安全存储引擎。
- InnoDB 是为处理巨大数据量的最大性能设计。它的 CPU 效率比其他基于磁盘的关系型数据库引擎高。
- InnoDB 存储引擎自带缓冲池,可以将数据和索引缓存在内存中。
- InnoDB 支持外键完整性约束。
- InnoDB 被用在众多需要高性能的大型数据库站点上
- InnoDB 支持行级锁
-
MyISAM
MyISAM 基于 ISAM 存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM 拥有较高的插入、查询速度,但不支持事物。
MyISAM主要特性有:
- 大文件支持更好
- 当删除、更新、插入混用时,产生更少碎片。
- 每个 MyISAM 表最大索引数是64,这可以通过重新编译来改变。每个索引最大的列数是16
- 最大的键长度是1000字节。
- BLOB和TEXT列可以被索引
- NULL 被允许在索引的列中,这个值占每个键的0~1个字节
- 所有数字键值以高字节优先被存储以允许一个更高的索引压缩
- MyISAM 类型表的 AUTO_INCREMENT 列更新比 InnoDB 类型的 AUTO_INCREMENT 更快
- 可以把数据文件和索引文件放在不同目录
- 每个字符列可以有不同的字符集
- 有 VARCHAR 的表可以固定或动态记录长度
- VARCHAR 和 CHAR 列可以多达 64KB
- 只支持表锁
-
MEMORY
MEMORY 存储引擎将表中的数据存储到内存中,为查询和引用其他表数据提供快速访问。
一般来说,对插入和并发性能要求较高的,或者需要外键,或者需要事务支持的情况下,需要选择 InnoDB,
插入较少,查询较多的场景,优先考虑 MyISAM。
一般在建表时添加
-
InnoDB 将一张表存储为两个文件
- demo.frm -> 存储表的结构和索引
- demo.ibd -> 存储数据,ibd 存储是有限的, 存储不足自动创建 ibd1, ibd2
- InnoDB 的文件创建在对应的数据库中, 不能任意的移动
-
MyISAM 将一张表存储为三个文件
- demo.frm -> 存储表的结构
- demo.myd -> 存储数据
- demo.myi -> 存储表的索引
- MyISAM 的文件可以任意的移动
-
一对一
- 在 A 表中有一条记录,在 B 表中同样有唯一条记录相匹配
- 比如: 学生表和成绩表
-
一对多 / 多对一
- 在 A 表中有一条记录,在 B 表中有多条记录一直对应
- 比如: 博客中的用户表和文章表
-
多对多
- A 表中的一条记录有多条 B 表数据对应, 同样 B 表中一条数据在 A 表中也有多条与之对应
- 比如: 博客中的收藏表
外键是一种约束。他只是保证数据的一致性,并不能给系统性能带来任何好处。
建立外键时,都会在外键列上建立对应的索引。外键的存在会在每一次数据插入、修改时进行约束检查,如果不满足外键约束,则禁止数据的插入或修改,这必然带来一个问题,就是在数据量特别大的情况下,每一次约束检查必然导致性能的下降。
出于性能的考虑,如果我们的系统对性能要求较高,那么可以考虑在生产环境中不使用外键。
-
构造数据
-
添加外键
-
尝试插入数据后在删除,分别先对主表和子表进行一次删除。
-
删除外键。
数据库事务及其他
事务主要用于处理操作量大、复杂度高、并且关联性强的数据。
比如说, 在人员管理系统中, 你删除一个人员, 你即需要删除人员的基本资料, 也要删除和该人员相关的信息, 如信箱, 文章等等, 这样, 这些数据库操作语句就构成一个事务!
在 MySQL 中只有 Innodb 存储引擎支持事务。
事务处理可以用来维护数据库的完整性, 保证成批的 SQL 语句要么全部执行, 要么全部不执行。主要针对 insert, update, delete 语句而设置。
在写入或更新资料的过程中, 为保证事务 (transaction) 是正确可靠的, 所必须具备的四个特性 (ACID):
-
原子性 (Atomicity) :
- 事务中的所有操作, 要么全部完成, 要么全部不完成, 不会结束在中间某个环节。
- 事务在执行过程中发生错误, 会被回滚 (Rollback) 到事务开始前的状态, 就像这个事务从来没有执行过一样。
-
一致性 (Consistency):
在事务开始之前和事务结束以后, 数据库的完整性没有被破坏。 这表示写入的资料必须完全符合所有的预设规则, 这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
-
隔离性 (Isolation):
并发事务之间互相影响的程度,比如一个事务会不会读取到另一个未提交的事务修改的数据。在事务并发操作时,可能出现的问题有: 脏读:事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。 不可重复读:在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这回导致锁竞争加剧,影响性能。另一种方法是通过MVCC可以在无锁的情况下,避免不可重复读。 幻读:在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。
事务的隔离级别从低到高有:
-
读取未提交 (Read uncommitted)
- 所有事务都可以看到其他未提交事务的执行结果
- 本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少
- 该级别引发的问题是——脏读(Dirty Read):读取到了未提交的数据
-
读提交 (read committed)
-
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)
-
它满足了隔离的简单定义:一个事务只能看见已经提交事务做的改变
-
这种隔离级别出现的问题是: 不可重复读(Nonrepeatable Read):
不可重复读意味着我们在同一个事务中执行完全相同的 select 语句时可能看到不一样的结果。
导致这种情况的原因可能有:
- 有一个交叉的事务有新的commit,导致了数据的改变;
- 一个数据库被多个实例操作时,同一事务的其他实例在该实例处理其间可能会有新的commit
-
-
可重复读 (repeatable read)
- 这是MySQL的默认事务隔离级别
- 它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行
- 此级别可能出现的问题: 幻读(Phantom Read):当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行
- InnoDB 通过多版本并发控制 (MVCC,Multiversion Concurrency Control) 机制解决幻读问题;
- InnoDB 还通过间隙锁解决幻读问题
-
串行化 (Serializable)
- 这是最高的隔离级别
- 它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。MySQL锁总结
- 在这个级别,可能导致大量的超时现象和锁竞争
-
-
持久性 (Durability):
事务处理结束后, 对数据的修改就是永久的, 即便系统故障也不会丢失。
-
开启事务:
BEGIN
或START TRANSACTION
-
提交事务:
COMMIT
, 提交会让所有修改生效 -
回滚:
ROLLBACK
, 撤销正在进行的所有未提交的修改 -
创建保存点:
SAVEPOINT identifier
-
删除保存点:
RELEASE SAVEPOINT identifier
-
把事务回滚到保存点:
ROLLBACK TO identifier
-
查询事务的隔离级别:
show variables like '%isolation%';
-
设置事务的隔离级别:
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
InnoDB 提供的隔离级别有
READ
UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
存储过程(Stored Procedure)是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象。
存储过程是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。
存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用。
-
优点
- 存储过程可封装,并隐藏复杂的商业逻辑。
- 存储过程可以回传值,并可以接受参数。
- 存储过程无法使用 SELECT 指令来运行,因为它是子程序,与查看表,数据表或用户定义函数不同。
- 存储过程可以用在数据检验,强制实行商业逻辑等。
-
缺点
- 存储过程,往往定制化于特定的数据库上,因为支持的编程语言不同。当切换到其他厂商的数据库系统时,需要重写原有的存储过程。
- 存储过程的性能调校与撰写,受限于各种数据库系统。
-
声明语句结束符,可以自定义:
存储过程中有很多的SQL语句,SQL语句的后面为了保证语法结构必须要有分号(;),但是默认情况下分号表示客户端代码发送到服务器执行。必须更改结束符
-
声明存储过程:
-
存储过程开始和结束符号:
-
变量赋值:
-
变量定义:
-
创建mysql存储过程、存储函数:
-
存储过程体:
-
简单用法
-
复杂一点的 (备注:只能在标准 mysql 客户端中执行,mycli 无法识别)
-
查看存储过程
-
删除存储过程
-
安装:
-
使用
什么是SQL注入?
SQL注入(SQLi)是一种注入攻击,,可以执行恶意SQL语句。它通过将任意SQL代码插入数据库查询,使攻击者能够完全控制Web应用程序后面的数据库服务器。攻击者可以使用SQL注入漏洞绕过应用程序安全措施;可以绕过网页或Web应用程序的身份验证和授权,并检索整个SQL数据库的内容;还可以使用SQL注入来添加,修改和删除数据库中的记录。
思考:下面的代码有没有问题?
-
备份
-
恢复
Redis 与 MongoDB
如今,大多数的计算机系统(包括服务器、PC、移动设备等)都会产生庞大的数据量。其实,早在2012年的时候,全世界每天产生的数据量就达到了2.5EB(艾字节)。这些数据有很大一部分是由关系型数据库来存储和管理的。实践证明,关系型数据库是实现数据持久化最为重要的方式,它也是大多数应用在选择持久化方案时的首选技术。
NoSQL 是一项全新的数据库革命性运动,虽然它的历史可以追溯到1998年,但是NoSQL真正深入人心并得到广泛的应用是在进入大数据时候以后,业界普遍认为NoSQL是更适合大数据存储的技术方案,这才使得NoSQL的发展达到了前所未有的高度。2012年《纽约时报》的一篇专栏中写到,大数据时代已经降临,在商业、经济及其他领域中,决策将不再基于经验和直觉而是基于数据和分析而作出。事实上,在天文学、气象学、基因组学、生物学、社会学、互联网搜索引擎、金融、医疗、社交网络、电子商务等诸多领域,由于数据过于密集和庞大,在数据的分析和处理上也遇到了前所未有的限制和阻碍,这一切都使得对大数据处理技术的研究被提升到了新的高度,也使得各种NoSQL的技术方案进入到了公众的视野。
NoSQL数据库按照其存储类型可以大致分为以下几类:
类型 | 部分代表 | 特点 |
---|---|---|
列族数据库 | HBase Cassandra Hypertable |
顾名思义是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的I/O优势,适合于批量数据处理和即时查询。 |
文档数据库 | MongoDB CouchDB ElasticSearch |
文档数据库一般用类JSON格式存储数据,存储的内容是文档型的。这样也就有机会对某些字段建立索引,实现关系数据库的某些功能,但不提供对参照完整性和分布事务的支持。 |
KV数据库 | DynamoDB Redis LevelDB |
可以通过key快速查询到其value,有基于内存和基于磁盘两种实现方案。 |
图数据库 | Neo4J FlockDB JanusGraph |
使用图结构进行语义查询的数据库,它使用节点、边和属性来表示和存储数据。图数据库从设计上,就可以简单快速的检索难以在关系系统中建模的复杂层次结构。 |
对象数据库 | db4o Versant |
通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。 |
Redis 是一种基于键值对的NoSQL数据库,它提供了对多种数据类型(字符串、哈希、列表、集合、有序集合、位图等)的支持,能够满足很多应用场景的需求。Redis将数据放在内存中,因此读写性能是非常惊人的。与此同时,Redis也提供了持久化机制,能够将内存中的数据保存到硬盘上,在发生意外状况时数据也不会丢掉。此外,Redis还支持键过期、地理信息运算、发布订阅、事务、管道、Lua脚本扩展等功能,总而言之,Redis的功能和性能都非常强大,如果项目中要实现高速缓存和消息队列这样的服务,直接交给Redis就可以了。目前,国内外很多著名的企业和商业项目都使用了Redis,包括:Twitter、Github、StackOverflow、新浪微博、百度、优酷土豆、美团、小米、唯品会等。
2008年,一个名为Salvatore Sanfilippo的程序员为他开发的LLOOGG项目定制了专属的数据库(因为之前他无论怎样优化MySQL,系统性能已经无法再提升了),这项工作的成果就是Redis的初始版本。后来他将Redis的代码放到了全球最大的代码托管平台
Redis是 remote dictionary server 的缩写,它是一个用 ANSI C 编写的高性能的key-value存储系统,与其他的key-value存储系统相比,Redis有以下一些特点(也是优点):
- Redis的读写性能极高,并且有丰富的特性(发布/订阅、事务、通知等)。
- Redis支持数据的持久化(RDB和AOF两种方式),可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis支持多种数据类型,包括:string、hash、list、set,zset、bitmap、hyperloglog等。
- Redis支持主从复制(实现读写分离)以及哨兵模式(监控master是否宕机并自动调整配置)。
- Redis支持分布式集群,可以很容易的通过水平扩展来提升系统的整体性能。
- Redis基于TCP提供的可靠传输服务进行通信,很多编程语言都提供了Redis客户端支持。
- 高速缓存 - 将不常变化但又经常被访问的热点数据放到Redis数据库中,可以大大降低关系型数据库的压力,从而提升系统的响应性能。
- 排行榜 - 很多网站都有排行榜功能,利用Redis中的列表和有序集合可以非常方便的构造各种排行榜系统。
- 商品秒杀/投票点赞 - Redis提供了对计数操作的支持,网站上常见的秒杀、点赞等功能都可以利用Redis的计数器通过+1或-1的操作来实现,从而避免了使用关系型数据的
update
操作。 - 分布式锁 - 利用Redis可以跨多台服务器实现分布式锁(类似于线程锁,但是能够被多台机器上的多个线程或进程共享)的功能,用于实现一个阻塞式操作。
- 消息队列 - 消息队列和高速缓存一样,是一个大型网站不可缺少的基础服务,可以实现业务解耦和非实时业务削峰等特性,这些我们都会在后面的项目中为大家展示。
可以通过在Redis的
在 redis 源代码目录下有一个名为redis.conf的配置文件,我们可以先查看一下该文件: vim redis.conf
-
配置将 Redis 服务绑定到指定的IP地址和端口。
-
设置后台运行 (以守护进程方式运行)
-
设置日志级别, 可选值: (
debug
: 调试,verbose
: 详细,notice
: 通知,warning
: 警告) -
配置数据库的数量, 默认为 16 个
-
配置数据写入规则
-
配置Redis的持久化机制 - RDB。
-
配置Redis的持久化机制 - AOF。
-
配置Redis的主从复制,通过主从复制可以实现读写分离。
-
配置慢查询。
接下来启动 Redis 服务器,下面的方式将以指定的配置文件启动 Redis 服务。
接下来用 Redis 客户端去连接服务器。
Redis有着非常丰富的数据类型,也有很多的命令来操作这些数据,具体的内容可以查看
Redis在运行时,所有的数据都保存在内存里,进程结束以后,会将数据写入到硬盘中。启动时,会读取硬盘里的内容,并将内容全部加载到内存中(会大量的占用内存)。
Redis的持久化有两种形式:RDB和AOF
默认的持久化方式,是对内存中的数据进行镜像,并以二进制的形式保存到dump.rdb文件中。会根据配置文件的时间节点对文件进行持久化。
优点:速度快,直接镜像内存里的数据,文件小。
缺点:数据有可能会丢失,在两次保存间隔内的数据,有可能会丢失。
AOF(Append only file)持久化,将修改的每一条指令记录进appendonly.aof中,需要修改配置文件,来打开aof功能。
优点:适合保存增量数据,数据不丢失。
缺点:文件体积大,恢复时间长
可以使用pip安装redis模块。redis模块的核心是名为Redis的类,该类的对象代表一个Redis客户端,通过该客户端可以向Redis服务器发送命令并获取执行的结果。上面我们在Redis客户端中使用的命令基本上就是Redis对象可以接收的消息,所以如果了解了Redis的命令就可以在Python中玩转Redis。
MongoDB是2009年问世的一个面向文档的数据库管理系统,由 C++ 语言编写,旨在为Web应用提供可扩展的高性能数据存储解决方案。虽然在划分类别的时候后,MongoDB被认为是NoSQL的产品,但是它更像一个介于关系数据库和非关系数据库之间的产品,在非关系数据库中它功能最丰富,最像关系数据库。
MongoDB将数据存储为一个文档,一个文档由一系列的“键值对”组成,其文档类似于JSON对象,但是MongoDB对JSON进行了二进制处理(能够更快的定位key和value),因此其文档的存储格式称为BSON。关于JSON和BSON的差别大家可以看看MongoDB官方网站的文章
目前,MongoDB已经提供了对Windows、MacOS、Linux、Solaris等多个平台的支持,而且也提供了多种开发语言的驱动程序,Python当然是其中之一。
可以从MongoDB的
说明:上面的操作中,export命令是设置PATH环境变量,这样可以在任意路径下执行mongod来启动MongoDB服务器。MongoDB默认保存数据的路径是/data/db目录,为此要提前创建该目录。此外,在使用mongod启动MongoDB服务器时,--bind_ip参数用来将服务绑定到指定的IP地址,也可以用--port参数来指定端口,默认端口为27017。
我们通过与关系型数据库进行对照的方式来说明MongoDB中的一些概念。
SQL | MongoDB | 解释(SQL/MongoDB) |
---|---|---|
database | database | 数据库/数据库 |
table | collection | 二维表/集合 |
row | document | 记录(行)/文档 |
column | field | 字段(列)/域 |
index | index | 索引/索引 |
table joins | --- | 表连接/嵌套文档 |
primary key | primary key | 主键/主键(_id 字段) |
启动服务器后可以使用交互式环境跟服务器通信,如下所示。
-
查看、创建和删除数据库。
-
创建、删除和查看集合。
说明:在MongoDB中插入文档时如果集合不存在会自动创建集合,所以也可以按照下面的方式通过创建文档来创建集合。
-
文档的CRUD操作。
使用MongoDB可以非常方便的配置数据复制,通过冗余数据来实现数据的高可用以及灾难恢复,也可以通过数据分片来应对数据量迅速增长的需求。关于MongoDB更多的操作可以查阅
可以通过pip安装pymongo来实现对MongoDB的操作。
行业资料:添加即可领取PPT模板、简历模板、行业经典书籍PDF。
面试题库:历年经典,热乎的大厂面试真题,持续更新中,添加获取。
学习资料:含Python、爬虫、数据分析、算法等学习视频和文档,添加获取
交流加群:大佬指点迷津,你的问题往往有人遇到过,技术互助交流。
领取