谈谈SQL和NoSQL数据库
一、概念
1、SQL数据库
SQL (Structured Query Language) 数据库,指关系型数据库。关系型数据库的内部设计由关系算法决定,这些系统需要预先定义一个模式(schema)和数据要遵守的类型。SQL是与这些系统交互的标准方式。
主要代表:SQL Server,Oracle,MySQL(开源),PostgreSQL(开源)。
2、NoSQL数据库
NoSQL(NoSQL= Not Only SQL ),意即“不仅仅是SQL”,是一项全新的数据库革命性运动。NoSQL的拥护者们提倡运用非关系型的数据存储。大多数数据库技术不能保证支持ACID(原子性、一致性、隔离性和持久性),而且大部分技术都是开源项目,这些技术作为整体被称为NoSQL。特征如下:
特征 | 描述 |
---|---|
不需要预定义模式 | 不需事先定义数据模式,预定义表结构等。数据中每条记录都可能有不同的属性和格式 |
无共享架构 | NoSQL往往将数据划分后存储在各个本地服务器上,从而提高了系统的性能 |
弹性可扩展 | 可以在系统运行的时候,动态增加或者删除结点。不需要停机维护,数据可以自动迁移 |
分区 | NoSQL数据库将数据进行分区,将记录分散在多个节点上面,并且通常分区的同时还要做复制 |
异步复制 | NoSQL中的复制,往往是基于日志的异步复制。这样,数据就可以尽快地写入一个节点,而不会出现网络传输迟延 |
BASE | 相对于ACID特性,NoSQL数据库保证的是BASE特性(BASE是最终一致性和软事务) |
主要代表:MongoDB,Redis,CouchDB。
二、区别
1、存储方式
SQL数据库中数据存在特定结构的表中;
而NoSQL数据库中则更加灵活和可扩展,存储方式可以是JSON文档、哈希表或者其他方式。
2、表/数据的关系
在SQL数据库中,必须定义好表和字段结构后才能添加数据,例如定义表的主键(primary key),索引(index),触发器(trigger),存储过程(stored procedure)等。表结构可以在被定义之后更新,但是如果有比较大的结构变更的话就会变得比较复杂;
在NoSQL数据库中,数据可以在任何时候任何地方添加,不需要先定义表。NoSQL数据库也可以在数据集中建立索引。以MongoDB为例,会自动在数据集合创建后创建唯一值_id字段,这样的话就可以在数据集创建后增加索引。
从这点来看,NoSQL数据库可能更加适合初始化数据还不明确或者未定的项目中。
3、外部数据存储
SQL数据库中如果需要增加外部关联数据的话,规范化做法是在原表中增加一个外键,关联外部数据表。
而在NoSQL数据库中除了这种规范化的外部数据表做法以外,我们还能用如下的非规范化方式把外部数据直接放到原数据集中,以提高查询效率。缺点也比较明显,更新审核人数据的时候将会比较麻烦。
4、JOIN查询
SQL数据库中可以使用JOIN表链接方式将多个关系数据表中的数据用一条简单的查询语句查询出来;
NoSQL数据库暂未提供类似JOIN的查询方式对多个数据集中的数据做查询,所以大部分NoSQL数据库使用非规范化的数据存储方式存储数据。
5、数据耦合性
SQL数据库中不允许删除已经被使用的外部数据,以保证数据完整性;
而NoSQL数据库中则没有这种强耦合的概念,可以随时删除任何数据。
6、事务
SQL数据库中如果多张表数据需要同批次被更新,即如果其中一张表更新失败的话其他表也不能更新成功,这种场景可以通过事务来控制,可以在所有命令完成后再统一提交事务;
而NoSQL中没有事务这个概念,每一个数据集的操作都是原子级的。
7、增删改查语法
MySQL | MongoDB | 说明 |
---|---|---|
mysqld | mongod | 服务器守护进程 |
mysql | mongo | 客户端工具 |
mysqldump | mongodump | 逻辑备份工具 |
mysql | mongorestore | 逻辑恢复工具 |
db.repairDatabase() | 修复数据库 | |
mysqldump | mongoexport | 数据导出工具 |
source | mongoimport | 数据导入工具 |
grant * privileges on . to … | Db.addUser();Db.auth() | 新建用户并权限 |
show databases | show dbs | 显示库列表 |
Show tables | Show collections | 显示表列表 |
Show slave status | Rs.status | 查询主从状态 |
Create table users(a int, b int) | db.createCollection(“mycoll”, {capped:true,size:100000}) | 创建表 |
Create INDEX idxname ON users(name) | db.users.ensureIndex({name:1}) | 创建索引 |
Create INDEX idxname ON users(name,ts DESC) | db.users.ensureIndex({name:1,ts:-1}) | 创建索引 |
Insert into users values(1, 1) | db.users.insert({a:1, b:1}) | 插入记录 |
Select a, b from users | db.users.find({},{a:1, b:1}) | 查询表 |
Select * from users | db.users.find() | 查询表 |
Select * from users where age=33 | db.users.find({age:33}) | 条件查询 |
Select a, b from users where age=33 | db.users.find({age:33},{a:1, b:1}) | 条件查询 |
select * from users where age<33 | db.users.find({‘age’:{$lt:33}}) | 条件查询 |
select * from users where age>33 and age<=40 | db.users.find({‘age’:{$gt:33,$lte:40}}) | 条件查询 |
select * from users where a=1 and b=’q’ | db.users.find({a:1,b:’q’}) | 条件查询 |
select * from users where a=1 or b=2 | db.users.find( { $or : [ { a : 1 } , { b : 2 } ] } ) | 条件查询 |
select * from users limit 1 | db.users.findOne() | 条件查询 |
select * from users where name like “%Joe%” | db.users.find({name:/Joe/}) | 模糊查询 |
select * from users where name like “Joe%” | db.users.find({name:/^Joe/}) | 模糊查询 |
select count(1) from users | Db.users.count() | 获取表记录数 |
select count(1) from users where age>30 | db.users.find({age: {‘$gt’: 30}}).count() | 获取表记录数 |
select DISTINCT last_name from users | db.users.distinct(‘last_name’) | 去掉重复值 |
select * from users ORDER BY name | db.users.find().sort({name:-1}) | 排序 |
select * from users ORDER BY name DESC | db.users.find().sort({name:-1}) | 排序 |
EXPLAIN select * from users where z=3 | db.users.find({z:3}).explain() | 获取存储路径 |
update users set a=1 where b=’q’ | db.users.update({b:’q’}, {$set:{a:1}}, false, true) | 更新记录 |
update users set a=a+2 where b=’q’ | db.users.update({b:’q’}, {$inc:{a:2}}, false, true) | 更新记录 |
delete from users where z=”abc” | db.users.remove({z:’abc’}) | 删除记录 |
db. users.remove() | 删除所有的记录 | |
drop database IF EXISTS test; | use test;db.dropDatabase() | 删除数据库 |
drop table IF EXISTS test; | db.mytable.drop() | 删除表/collection |
db.addUser(‘test’, ’test’) | 添加用户,readOnly–>false | |
db.addUser(‘test’, ’test’, true) | 添加用户,readOnly–>true | |
db.addUser(“test”,”test222”) | 更改密码 | |
db.system.users.remove({user:”test”})或者db.removeUser(‘test’) | 删除用户 | |
use admin | 超级用户 | |
db.auth(‘test’, ‘test’) | 用户授权 | |
db.system.users.find() | 查看用户列表 | |
show users | 查看所有用户 | |
db.printCollectionStats() | 查看各collection的状态 | |
db.printReplicationInfo() | 查看主从复制状态 | |
show profile | 查看profiling | |
db.copyDatabase(‘mail_addr’,’mail_addr_tmp’) | 拷贝数据库 | |
db.users.dataSize() | 查看collection数据的大小 | |
db. users.totalIndexSize() | 查询索引的大小 |
8、查询性能
在相同水平的系统设计的前提下,因为NoSQL中省略了JOIN查询的消耗,故理论上性能上是优于SQL的。
三、补充
目前许多大型互联网项目都会选用MySQL(或任何关系型数据库) + NoSQL的组合方案
关系型数据库适合存储结构化数据,如用户的帐号、地址:
- 这些数据通常需要做结构化查询,比如join,这时候,关系型数据库就要胜出一筹
- 这些数据的规模、增长的速度通常是可以预期的
- 事务性、一致性
NoSQL适合存储非结构化数据,如文章、评论:
- 这些数据通常用于模糊处理,如全文搜索、机器学习
- 这些数据是海量的,数据模型比较简单,而且增长的速度是难以预期的,
- 根据数据的特点,NoSQL数据库通常具有无限(至少接近)伸缩性
- 按key获取数据效率很高,但是对join或其他结构化查询的支持就比较差
- 不需要高度的数据一致性
基于它们的适用范围不同,目前主流架构才会采用组合方案,一个也不能少。目前为止,还没有出现一个能够通吃各种场景的数据库。