数据存储和消息队列
数据库
1. MySQL 索引使用的注意事项
- 索引不会包含有Null值的列
只要列中包含有null值都将不会被包含在索引中。符合索引中只要有一列含有null值,那么这一列对于此符合索引就是无效的。 - 使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如有一个char(255)的列,如果在前10或20个字符内,多数值是惟一的,就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。 - 索引列排序
MySQL查询只使用一个索引。因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作,尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。 - like语句操作
一般情况下不鼓励使用like操作。如果非使用不可,尽量避免%aaa%,因为不会使用索引,而like"aaa%"则会使用索引。 - 不要在列上进行运算
select * from users where YEAR(adddate)<2007
将在每个行上进行运算,这将导致索引失效而进行全表扫描。可以改为
select * from users where adddate<'2007-01-01'
- 不使用Not IN,<>,!=操作,但<,<=,=,>,>=,between,in是可以使用索引的
- 索引要建立在经常进行select操作的字段上
- 索引要建立在值比较唯一的字段上。
- 对于那些定义为text,image和bit数据类型的列不应该增加索引。因为这些列的数据量要么相当大,要么取值很少。
- 在where和join中出现的类需要建立索引
- where的查询条件里有不等号(where column != ...),mysql将无法使用索引
- 在join操作时,MySQL只有在主键和外键的数据类型相同时才能使用索引,否则即使建立了索引也不会使用。
参考:
《mysql索引使用技巧及注意事项》
《MySQL索引类型总结和使用技巧以及注意事项》
2. DDL、DML、DCL分别指什么
- 数据库操纵语言DML data mamipulation language:
select, update, insert, delete。
用于对数据库的数据进行一些操作 - 数据库定义语言DDL Data Define Language:
create, alter, drop等。
DDL主要用在定义或改变表的结构,数据类型,表之间的链接和约束等初始化工作上。 - 数据库控制语言DCL Data Control Language:
grant, deny, revoke等。
用来设置或更改数据库用户或角色权限的语句。
3. explain命令
MySQL的explain命令用于SQL语句的查询执行计划QEP。这条命令的数据结果能够让我们了解到MySQL优化器是如何执行SQL语句的。
这条命令并没有提供任何调整建议,但它能够提供重要的信息来帮助做出调优决策。
MySQL的explain语法可以运行在select语句或者特定表上。如果作用在表上,那么此命令等同于dedsc表命令。使用在select语句上时,只需要在SQL语句开始前加上explain。
4. left join,right join,inner join
4.1 内连接inner join
内连接使用比较运算符根据每个表公有的列的值匹配两个表中的行。
4.2 左外链接left join
左外链接的结果集包括子句中指定的左表的所有行,而不仅仅是连接列所匹配的行。如果左表的某行在右表中没有匹配行,则结果集中国此行右表的所有选择列表均为空值。
4.3 右外链接right join
右外连接是左外连接的反向链接,将返回右表的所有行,没有匹配数据时处理方式与左外连接相同。
5. 数据库事物ACID(原子性、一致性、隔离性、持久性)
- 原子性:
事务不可分割,组成事务的各个逻辑单元不可分割 - 一致性:
事务执行的前后,数据完整性保持一致 - 隔离性:
事务执行不应该受到其他事务的干扰 - 持久性:
事务一旦结束,数据就持久化到数据库中
6. 事物的隔离级别(读未提交、读以提交、可重复读、可序列化读)
6.1 Read Uncommitted读未提交
一个事务可以读取另一个未提交事务的数据。此隔离级别不能解决脏读,不可重复读和幻读问题。
6.2 Read Committed读提交
一个事务要等另一个事务提交后才能读取数据。若有事务对数据进行update操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,,可以解决脏读,但无法解决不可重复读和幻读。
大多数据库默认为此隔离级别,如SQL Server和Oracle。
6.3 Repeatable Read重复读
开始读取数据(事务开启)时,不允许修改update操作。重复读可以解决脏读和不可重复读问题,但无法解决幻读问题。
MySQL数据库默认为此隔离级别。
6.4 Serializable序列化
序列化是最高的事务隔离级别。在该级别下,事务串行化顺序执行,此级别以锁表的方式使得其他的线程只能在锁外等待,所以效率最为低下,非常消耗数据库性能。序列化可以解决脏读,不可重复读和幻读问题。
参考:
《理解事务的4种隔离级别》
7. 脏读、幻读、不可重复读
7.1 脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
当一个事务正在多次修改一个数据,而在这个事务中这多次的修改都还未提交,这时如果一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。
7.2 不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却反悔了不同的数据值。这时由于查询间隔,被另一个事务修改并提交了。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
7.3 幻读(虚读)
幻读是事务非独立执行时发生的一种现象。读取的是另一个事务insert的数据。幻读的重点在于新增或者删除(数据条数发生变化)
例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样.
幻读和不可重复读都是读取了另一条已经提交的事务(脏读是读取未提交的事务),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体。
参考:
《数据库事务的四大特性以及事务的隔离级别》
《对于脏读,不可重复读,幻读的一点理解,看懂红字很关键》
8. 数据库的几大范式
8.1 第一范式1NF
数据库表的每一列都是不可分割的基本数据项。例如电话号码这个属性可以被继续分割为办公电话,手机号码等属性,在第一范式的语义下不应该作为单独的一列出现。
在任何一个关系数据库中,第一范式是对关系模式的基本要求,不满足第一范式的数据库就不是关系数据库。
8.2 第二范式2NF
在满足第一范式的情况下,数据库表中的每一行必须是可以被唯一地区分,即每一行中有一个唯一表示将这行与其他行区分出来。这个唯一标示就是主键。
2NF的语义下,所有非主键的字段都要依赖主键。第二范式就是一个有唯一主键在表中保证每一行都是唯一的,存在一个列被定义为唯一主键的表就是第二范式。
8.3 第三范式3NF
在满足第一第二范式的前提下,非主键字段斗鱼主键字段有直接依赖关系,不存在传递依赖。即非主键字段只依赖主键字段,而不依赖其他的非主键字段。
第三范式就是父子两张表,在子表中的外键是父表的主键,子表中的外键值必须是父表中的主键值。
8.4 鲍依斯-科得范式BCNF
在第三范式的基础上,数据库表中如果不存在任何字段对任一候选关键字段的传递函数依赖则符合第三范式。
8.5 第四范式4NF
第四范式用于处理复杂的复合主键所导致的问题。第四范式用来识别那些需要花费为多个不同的实体。
第四范式就是在一个没有段独立列被定义为唯一主键的表中用多个列组合一起被定义为唯一主键。用复合列做主键的表就是第四范式。
参考:
《数据库的四个范式之间的区别》
《对关系型数据库五个范式的理解》
《[学习笔记]数据库设计三大范式与BCNF,学习笔记》
9. 数据库常见的命令
由于篇幅所限,这里只给出相关链接。
参考:
《mysql数据库常用命令》
《数据库常用命令概括》
10. 说说分库与分表设计
当单表数据量达到一定规模,比如千万级别(对于MySQL而言当数据量超过200万是就会有很严重的查询速度限制了),此时做很多操作都会相当费时费力,所以可以考虑进行分表处理。
数据的切分Sharding根据其切分规则的类型,可以分为两种切分模式:一种是按照不同的表或者schema来切分到不同的数据库之上,这种切割称为垂直切分;另一种则是根据表中的数据的逻辑关系将同一个表中的数据按照条件拆分到多态数据库上面,称为水平切分。
分表常用方式:
- 使用时间作为依据分库/分表
- 是用数字作为分库/分表的标准
- 使用MD5区分
垂直切分(业务切分)
- 拆分后俄舞清晰,拆分规则明确
- 系统之间整合或扩展容易
- 数据维护简单
- 部分业务表无法join,只能通过接口方式解决,提高了系统复杂度。
- 受每种业务不同的限制存在单裤性能瓶颈,不易数据扩展跟性能提高。
- 事务处理复杂。
垂直切分是按照业务的分类将表分散到不同的库,所以有些业务表会过于庞大,存在单库读写与存储瓶颈,所以就需要水平拆分来做解决。
水平切分
相较于垂直拆分,水平拆分不是将表做分类,而是按照某个字段的某种规则来分散到多个库之中。诶个表中包含一部分数据。水平切分是按照数据行的切分,将表中的某些行切分到一个数据库,而另外的某些行又切分到其他的数据库中。
水平切割优点:
- 拆分规则抽象好,join操作较简单
- 不存在单库大数据,高并发的性能瓶颈。
- 应用端改造较少
- 提高了系统的稳定性跟负载能力
缺点:
- 拆分规则难以抽象
- 分片事务一致性难以解决
- 数据多次扩展难度跟维护量极大
- 跨库join性能较差
参考:
《千万数据的分库分表(一)》
《分表与分库使用场景以及设计方式》
《浅谈分库分表》
11. 分库与分表带来的分布式困境与应对之策(如何解决分布式下的分库分表,全局表?)
这题有点。。。太大神级别了,我这种菜鸟很难在短时间内消化这类的知识博客。本着不误人子弟的原则,由于我没有彻底理解一些资料的说法,因此不在这里给出我的答案,只给出一些参考链接,如果有人能有比较好的答案,欢迎给出。
《分库分表的几种常见玩法及如何解决跨库查询等问题》
《每日学习20170224-分库分表全局ID生成》
12. 说说 SQL 优化之道
- 使用truncate代替delete
oracle执行delete后会将被删除的数据存放到undo表空间以便回复。如果用户使用rollback而不是commit,则oracle会利用undo表空间中的数据进行恢复。而使用truncate时,oracle不会将被删除的数据放入undo表空间,因而速度要快很多。 - 活用commit
PL/SQL块中,经常将几个互相联系的DML语句卸载BEGIN...END,如果不影响事务的完整性,则建议在每个END前面写一个commit,以达到对DML的即使提交和释放事务所占资源的目的。 - where子句书写
oracle优化器的原理是采用自下而上的顺序解析where子句,因此表之间的连接永远写在where后面的第一个位置,并对过滤条件进行估算,可过滤掉最大数量纪录的条件必须写在where子句的末尾。 - 取别名
联合表的查询中,表名和列名以一个字母为别名可以提高1.5倍查询速度 - 充分利用索引
如果检索全表,不必建索引。因为索引会带来额外的IO操作,如果检索的数据记录数占全部表记录的10%以下,可以考虑建索引。
表之间的关联字段可以考虑建索引。
如果表的记录数较少时,不建议使用索引,如数据不超过一万行的表不要建立索引。 - 不要有超过五个以上的表连接(JOIN)
连接的表越多,其编译的时间和连接的开销也越大,性能越不好控制。最好把连接拆开成较小的几个部分逐个顺序执行。优先执行那些能够大量减少结果的连接。 - 尽量避免使用select *
返回的结果越大,意味着相应的SQL语句的logical reads就越大,对服务器的性能影响就越甚。 - 使用存储过程
可以考虑使用存储过程封装那些复杂的sql语句或逻辑。存储过程的执行计划可以被缓存在内存中较长时间,减少了重新编译的时间,而且减少了客户端和服务器的繁复交互。 - 注意一些sql语句将会使引擎放弃使用索引而进行全盘扫描。应尽量避免类似sql语句的使用
!=,<>, or会导致引擎不走索引。
避免在where子句中对字段进行null值判断,否则不走索引。
like'%abc%'不走索引(前置百分号不走索引,后置走)
in和not in也要慎用,否则导致全表扫描。可以用between代替。
where子句中使用参数也会导致放弃使用索引。因为sql只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时。
where子句中对字段进行表达式或函数操作会导致放弃使用索引。 - 尽量避免使用游标
游标效率较差,如果游标啊哦做的数据超过一万行,那么就应该考虑改写。 - 尽量避免滥用distinct和order by。跟union一样,它们增加了额外的开销,使查询变慢。
- 尽量少使用视图
视图效率很低,对视图操作比直接对表操作慢。可以使用stored procedure来代替它。特别注意不要使用视图嵌套。视图嵌套增加了寻找原始资料的难度。
参考:
《高级sql优化详解》
《sql优化心得》
《数据库SQL优化大总结之 百万级数据库优化方案》
13. MySQL遇到的死锁问题、如何排查与解决
13.1 MySQL常用存储引擎的锁机制
MyISAM和MEMORY采用表级锁table-level locking。
BDB采用页面锁page-level locking或表级锁,默认为页面锁。
InnoDB支持行级锁row-level locking和表级锁,默认为行级锁。
13.2 锁特点
表级锁:开销小,加锁快;不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁。锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间介于表锁和行锁之间;会出现死锁。锁定粒度介于表锁和行锁之间并发度一般。
13.3 锁的使用场景
表级锁更适合以查询为主,只有少量按索引条件更新数据的应用。
行级锁更适合有大量按索引条件并发更新数据,同时又有并发查询的应用,如一些在线事务处理系统。
13.4 死锁的出现
在MySQL中,行级锁并不是直接锁记录,而是锁索引。索引分为朱建索引和非主键索引两种。如果一条sql语句操作了主键索引,MySQL就会锁定这条主键索引;如果一条语句操作了非主键索引,MySQL就会先锁定该非主键索引,再锁定相关的主键索引。
在update。delete操作时,MySQL不仅锁定where条件扫描过的所有索引记录,而且会锁定相邻的键值。
用户A查询一条纪录,然后修改该条纪录;这时用户B修改该条纪录,这时用户A的事务里锁的性质由查询的共享锁企图上升到独占锁,而用户B里的独占锁由于A 有共享锁存在所以必须等A释放掉共享锁,而A由于B的独占锁而无法上升的独占锁也就不可能释放共享锁,于是出现了死锁。这种死锁比较隐蔽,但在稍大点的项 目中经常发生。
13.5 死锁的检测与处理
MySQL有自己的死锁检测,如果发现出现了死锁,会自行kill掉相关线程并在status里留下一条记录以供查询。
排查死锁时,首先要根据死锁日志来分析循环等待的场景,然后根据当前各个事务执行的sql分析出家锁类型以及顺序,意向推断出如何形成循环等待,以期找到死锁产生的原因。
MySQL的死锁绝大部分情况都是由于不良好的代码造成的,因此提高代码的质量是最根本的解决办法。
参考:
《mysql数据库死锁的产生原因及解决办法》
《MySQL死锁问题分析及解决方法实例详解》
14. 存储引擎的 InnoDB与MyISAM区别,优缺点,使用场景
MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。MyISAM在所有MySQL配置里都被支持,它是默认的存储引擎。
InnoDB提供事务安全表。
14.1 存储结构:
每个MyISAM在磁盘上存储成三个文件,第一个文件的名字以表的名字开始,扩展名支出文件类型。.frm文件存储表的定义。数据文件的扩展名为.MYD,索引文件的扩展名是.MYI。
InnoDB所有的表都保存在同一个数据文件中(也有可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统的大小,一般为2GB。
14.2 存储空间
MyISAM可被压缩,存储空间较小。
InnoDB的表需要更多的内存和存储。他会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。
14.3 可移植性,备份及恢复
MyISAM的数据以文件形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可以针对单独某个表进行操作。
InnoDB比较麻烦,可以选择拷贝数据文件,备份binlog或者使用MySQLdump。但在数据量达到几十g的情况下会相当麻烦。
14.4 事务安全
MyISAM每次查询具有原子性,不支持事务。
InnoDB支持事务,是具有崩溃修复能力的事务安全型表。
14.5 sql语句效率
MyISAM在select语句执行上更优。
而InnoDB在insert,update,delete语句更优。
如果没有where子句的count,则是MyISAM更优,因为它保存了表的具体行数,而InnoDB需要进行逐行统计扫描。
14.6 锁
MyISAM只支持表锁。
InnoDB支持表锁,行锁。但InnoDB的行锁只对where的主键有效,非主键的where都会锁全表。
14.7 外键
MyISAM不支持外键而InnoDB支持。
总之,InnoDB的设计目标是处理大容量数据库系统,他的cpu利用率是其他基于磁盘的关系数据库引擎所不能比的。InnoDB可以应对更为复杂的情况,特别是对并发的处理要比MyISAM高效。
参考:
《MySQL存储引擎MyISAM与InnoDB的优劣》
《MySQL存储引擎InnoDB与Myisam的六大区别》
15. 索引类别(B+树索引、全文索引、哈希索引)、索引的原理
B+树是一个平衡的多叉树,从根节点到叶子节点的高度差值不超过1,而且同层级的节点间有指针互相链接。
在B+树上的常规检索,从根节点到叶子结点的搜索效率基本相当,不会出现大幅波动,而且基于索引的顺序扫描时,也可以利用双向指针快速左右移动,效率非常高。
哈希索引采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子结点逐级查找,只需要一次哈希算法即可like定位到相应的位置,速度非常快。
哈希索引对范围查询检索无效,因为经过哈希算法后无法保证有序性。同理,哈希索引也无法利用索引完成排序,以及like这样的模糊查询。
全文索引是目前搜索引擎使用的一种关键技术。其实现非常复杂,是通过词来进行检索的。
MySQL对索引定义为:是帮助MySQL高效获取数据的数据结构。
在数据之外,数据库系统还维护着满足特定查找算法的数据结构。这些数据结构以某种方式引用(指向)数据。这样就可以在这些数据结构上实现高级查找算法。而这种数据结构就是索引。
索引是对数据库表中一个或多个列的值进行排序的结构。与在表中搜索所有的行相比,索引用指针指向存储在表中指定列的数据值,然后根据指定的次序排序这些指针,有助于快速地获取信息。
参考:
《MySQL索引背后的数据结构及算法原理》
《MySQL B+树索引和哈希索引的区别》
16. 什么是自适应哈希索引(AHI)
InnoDB存储引擎会监控对表上索引的查找,如果观察到建立哈希索引可以带来速度的提升,则建立哈希索引,所以称之为自适应。
自适应哈希索引通过缓冲池的B+树构造而来,因此建立的速度很快。而且不需要将整个表都建立哈希索引,InnoDB会自动根据访问的频率和模式来为某些页建立哈希索引。
自适应哈希索引由MySQL自动管理,无法人为干预,但可以通过参数innodb_adaptive_hash_index来禁用或启动此特性,默认是开启
参考:
《MySQL中自适应哈希索引》
《MySql 自适应哈希索引》
17. 为什么要用 B+tree作为MySQL索引的数据结构
二叉查找树的变种红黑树也可以用于实现索引,但文件系统及数据库系统普遍采用B+树作为索引结构。
一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存的存取,I/O的存取消耗是及其大的。
所以,评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。也就是说,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数。
数据库系统利用了磁盘的预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对其的,就实现了一个node只需一次I/O。
而红黑树这种结构,逻辑上很近的节点物理上可能很远,无法利用局部性,所以红黑树的效率比B+树要差很多。
参考:
《数据库为什么要用B+树结构--MySQL索引结构的实现》
18. 聚集索引与非聚集索引的区别
聚集索引:数据行的物理顺序与列值(一般是主键列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。
非聚集索引:该索引中索引的逻辑顺序与磁盘上的物理存储顺序不同,一个表中可以拥有多个非聚集索引。
参考:
《聚集索引与非聚集索引的总结》
《【数据库SQL】——聚集索引和非聚集索引根本区别以及使用方式》
19. 遇到过索引失效的情况没,什么时候可能会出现,如何解决
除过某些sql语句是会不走索引的,导致不走索引的还有其他的可能性:
- 使用了Oracle的move操作,此操作将导致索引失效
- 对分区表进行了删除,添加,合并,分割等操作将有可能导致Oracle数据库的索引失效。
这些Oracle索引失效的原因基本都是因为rowid改变了,从而导致了索引失效。因此建议在执行相应sql语句后附加update indexes子句来使Oracle自动维护全局索引以防失效。
20. limit 20000 加载很慢怎么解决
当一个数据库表过于庞大,Limit offset,length中的offset过大会导致查询语句非常缓慢,因为要扫描的数据太过于庞大。
limit分页优化法:
- 子查询优化法
先找出第一条数据,然后大于等于这条数据的id就是要获取的数据。但数据必须是连续的,也就是不能有where条件,where会筛选数据导致数据失去连续性。 - 倒排表优化法
类似建立索引,用一张表来维护页数,然后通过高效的连接来获得数据。但只合适数据数固定的情况,数据不能删除,维护页表非常困难。 - 反向查找优化法
当偏移量超过一半记录数的时候,先用排序,这样便宜就反转了。但对于order by的优化相当麻烦,要增加索引,而且必须要知道总记录数因为要在偏移大于数据总数一半时反转。 - limit限制优化法
把limit偏移量限制低于某个数,超过则不予查询。相当暴力的手段,但听说阿里的dba是这么干的。。。 - 只查索引法
优化后的子查询只读索引。
参考:
《MYSQL分页limit速度太慢的优化方法》
《mysql优化limit查询语句的5个方法》
21. 如何选择合适的分布式主键方案
在只使用单数据库时,自增主键是一个相当广泛的选择。但当使用分布式的集群架构时,对大表进行水平分表,就不能使用自增id,因为insert的记录插到哪个分表依分表规则判定决定。如果是自增id,则各个分表中id就会重复,导致查询,删除时出现异常。而如果只是集群的分布式架构而没有采用水平分表,则可以考虑使用自增id来作为主键。但也会存在主键全局唯一性地问题。
那么另一种使用普遍的主键,uuid,也不适合作为某些数据库的主键。例如InnoDB这种聚集主键类型的引擎,数据按照主键进行排序。而UUID的无序性让InnoDB产生巨大的IO压力,因此不适合作为物理主键,但可以作为逻辑主键。
也可以使用GUID来作为主键。GUID维护简单,实现容易。但计算成本很大,且GUID长度过大,浪费存储空间。
通过集群标号加集群内的自增两个字段共同组成唯一的主键。实现与维护简单,对应用透明。
对于分布式系统来说,全局唯一性至关重要,主键必须是唯一的,以防引起异常。其次关注性能问题,存储占用不能过大,主键的获取不能过于复杂否则影响插入效率。
参考:
《分布式环境下数据库主键方案》
22. 选择合适的数据存储方案
此题有歧义,不知道问的是数据存储设备的选择还是数据库的选择。在这里以数据库的选择进行解答。
22.1 关系型数据库MySQL
MySQL是一个最流行的开源关系型数据库。通常情况下MySQL数据库是第一选择方案。
22.2 内存数据库Redis
随着数据量增长,MySQL已经无法满足大型互联网类应用的需求。因此,Redis基于内存存储数据,可以极大的提高查询性能,对产品在架构上时很好的补充。Redis是典型的以空间换时间的策略,使用更多的内存换取CPU资源,通过增加系统的内存消耗,来加快程序的运行速度。
22.3 文档数据库MongoDB
MongoDB是对传统关系型数据库的补充,非常适合高伸缩性的场景,是可扩展性的表结构。MongoDB适合存储大尺寸的数据和海量的日志数据。它利用分片集群支持海量数据,同时使用聚集分析和MapReduce的能力。
22.4 非关系型数据库NoSQL
非关系型数据库以键值对存储,它的结构不固定,每一个元组可以有不一样的字段。每个元组可以根据需要增加一些自己的键值对,这样就不会局限于固定的结构,可以减少一些时间和空间的开销。所有非关系型数据库都是NoSQL数据库。
(这里的NoSQL略有重复,因为MongoDB,redis,hbase都是NoSQL数据库)
22.5 列数据库HBase
HBase适合海量数据的存储和高性能实时查询,它运行于HDFS文件系统之上,并且作为MapReduce分布式处理的目标数据库,以支撑离线分析型应用。
参考:
《服务端指南 数据存储篇 | 选择合适的数据存储方案》
23. 常见的几种分布式ID的设计方案
23.1 UUID
UUID保证了唯一性,只能有计算机生成,不需要远程调用,时延低,性能高;但UUID过长,不适合做索引字段而且无序,对于部分数据库引擎不友好。
23.2.采用自增机制+其他字段来保证唯一性自增ID
此机制确保id唯一性,而且充分接住了数据库的自增ID机制,可靠性高,生成了有序的ID。但相当依赖于数据库,且对于附加字段的选取需要一定的技术。
23.3 类snowflake方案
生成一个64位数字,该数据被划分为多个段,分别表示时间戳,机器编码,序号。
它时间戳在高位,自增序列在低位,整个ID是趋势递增的,按照时间有序,且高性能,可以根据业务需求灵活调整区段划分。但其依赖于及其时钟,而且过长,且由于涉及到分布式环境,每台及其上的时钟不可能完全同步,可能会出现不是全局递增的情况。
除此之外还有很多的id设计方案,可以参考附加的链接。在这里由于篇幅就不予详细讲解了。
参考:
《分布式ID方案有哪些以及各自的优劣势,我们当如何选择》
《分布式系统唯一ID生成方案汇总》
24. 常见的数据库优化方案,在你的项目中数据库如何进行优化的
这个问题请甩给DBA,如果没有DBA。。。
数据库物理层:
- 数据库系统软件应该尽量跟数据文件分置不同存储设备
- 如果可能,数据库临时空间,log尽量使用快速存储设备。
- 数据文件应该根据具体应用需要分置于不同存储设备来提高读取效率
- 数据文件使用RAID。RAID5无敌!
数据库逻辑层:
- 为数据库的system表空间,user表空间,应用表弓箭分离。如果可能,三类表空间应该分在不同的物理存储上。
- 应用表空间中表的表空间,索引的表空间也应该分离
- 创建表时应考虑表所存储数据的业务特性在创建时定义不同的起始空间和空间增长方案,以尽量让一条记录处于一个连续的物理存储空间来提高读取效率。
- 制定不同的备份恢复和碎片整理机制
- 索引并不是越多越好,数据变化频繁的表还应该建立索引定期重建机制,否则索引不但不会改善性能还会降低性能。
数据应用层:
- modeling必须要合理,数据库建模是重中之重。一个良好设计的数据库天生就具有优势,而一个设计不合理的数据库再怎么优化也是难以解决问题的。
- sql语句优化。这点太大了,比如查询尽量使用索引,尽量避免全表扫描,慎用子查询和Union all,夺标join时尽量用小表去join大表。
参考:
《有哪些常见的数据库优化方法?》