如何优化数据库布局? (数据库布局)

数据库布局是数据库设计与管理的重要一环,好的数据库布局可以极大地提高数据库的性能与可维护性。因此,在数据库设计的过程中,优化数据库布局是一个至关重要的步骤。

下面将从以下三个方面探讨如何优化数据库布局:表设计、数据类型选择与索引设计。

一、表设计

在数据库设计中,表设计是最为基础性的设计。因此,对表的设计需要特别重视。

1. 规范化设计

规范化是指将相对松散的数据结构转化为规范的关系型数据库模式。规范化设计是数据库设计的重要策略之一,可以避免数据冗余,提高数据的一致性和完整性。在表设计时,要根据实际需求对数据进行规范化设计。规范化设计是一个以数据为中心的过程,它注重数据之间的关系,而非表间关系。正确的规范化设计可以避免数据冗余,实现数据的一致性和完整性。

2. 主键设计

表设计还需要使用正确的主键,主键不仅是该表的唯一标识符,还是该表与其他表的关系的建立基础。在设计主键时,要遵循以下原则:简洁性、稳定性、唯一性、简单性。

二、数据类型选择

在数据库设计中,选择合适的数据类型可以极大地影响系统的性能。

1. 数字类型选择

数据库中使用的数字类型主要包括int、bigint、float、double、decimal等。在选择数字类型时,要根据实际需要选择正确的数据类型。一般来说,越小的数据类型速度越快,但存储的大小也越小。如果需要处理很大的数字,可以使用bigint等大号整型。如果需要进行小数计算,可以使用float和double。如果需要精确计算可以使用decimal类型。

2. 字符串类型选择

在数据库中使用的字符串类型主要包括char、varchar、text等。在设计字符串类型时,要根据实际需要选择正确的数据类型。一般来说,如果字符的长度是在30个字符以内,可以使用char类型;如果字符的长度不固定,可以使用varchar类型; 如果存储的内容比较大,可以使用text类型。

三、索引设计

索引是数据库中的一种重要资源,对于提高数据库性能有着至关重要的贡献。

1. 建立主键索引

主键索引是一种特殊的索引,它是根据主键列建立的。主键是唯一的,所以主键索引非常快,对于查询单个行和排序非常有用。

2. 建立唯一索引

唯一索引是一种特殊的索引,它能够保证索引列的唯一性。它通常用于约束模式中的某些字段,如账户名、手机号码等。如果需要对表进行大量的查找和统计操作,可以建立唯一索引。

3. 建立复合索引

复合索引是指将多个列的索引组合在一起,用于提高联合查找的效率。通过合理地建立复合索引,可以提高查询的效率,减少对物理存储的访问次数,从而提高查询性能。

优化数据库布局是数据库设计中的一项关键步骤。正确的数据库布局可以提高数据库的查询效率,降低系统崩溃和数据丢失的风险,从而提高数据库的可靠性和可扩展性。因此,数据库设计人员在进行数据库设计时,需要遵循规范化设计原则,选择正确的数据类型,并合理地建立索引,从而优化数据库布局。

相关问题拓展阅读:

如何自己实现一个关系型数据库

先写一个并发控制子系统。里面要提供各种各样的闩锁。包括具有不同相容性矩阵的,有优先队列或者没有的,能指数后退或者不能的,全局可追踪的或者不可追踪的,等等等等。

后写一个存储管理子系统。在这里你可以决定你的数据库的外存布局。比如一个表可不可以分开几个文件存,有没有区的概念,有没有段的概念,有没有表空间的概

念,它们之中谁是定长的,谁是可变长的,谁是空间申请单位,谁是空间调度单位。决定好了开始设计页区段表空间格式,它们的描述符格式,然后用页头,页记

录,页尾有的没的串一起。设计好了开始决定这个子系统有哪些内存对象,至少要有一个存储管理器用来初始化,分配或者调度存储单元,至少还要提供一堆方法来

决定怎么把二进制数据变成有意义的数据,比如读一个ushort, 写一个uint64等等。

之后就要开始写一个缓冲区管理子系统(假设

你做的不是一个内存数据库)。先弄明白什么是一个谈激block,一个page,

一个frame。这些都是你的类。然后写一个缓冲池,再写一个缓冲区管理器。缓冲池规定数据在内存上的布局,缓冲区管理器就是这个系统的接口了,可以回应

一个页的申请,并实现你最心仪的页替换策略。

再之后要写一个日志系统。先想好你是要用shadow

page日志啊,还是ARIES算法日志啊。假设用后者,于是你就失去了强制写,并采用偷帧的技术。这样你要设计redo日志的格式,并使你的日志记录种

类可扩展,因为不一定什么时候你就会需要一种新的日志记录。如果想让你的系统更稳健含哪袜,看看需不需要组日志(一组日志记录要么都重做要么都不重做)。如果想

让你的系统更高效,看看需不需要mvcc。要的话还得再加入undo日志,并设计格式。下面你要设计日志记录粒度。全物理日志?全逻辑日志?物理逻辑日

志。总之,逻辑的成分越多,系统设计越复杂(比如糟糕的部分写怎么处理)。最后跟存储管理系统要个地方物化日缓好志,再管缓冲区管理系统要个地方用来调度日志

页。

接下来要写一个锁系统。先想好你的系统是表级锁还是页级锁还是行级锁。前两个最自然,直接用fix

number什么的就搞定,最后一个你要有用来表示行锁的额外数据结构。每个行一个锁实例?每个页共用一坨锁实例?之后去这个锁表,用来统一申请释放锁。

最后再决定如何解决死锁,超时抛出异常?依赖图分析?

再接下来要写一个事务子系统。它无非就是提供了一些方法确保各种操作正确地使用了二

阶段锁,正确地写了日志,正确地回滚。但是这个系统的架构由”各种操作”的多样性决定。相比堆文件,对b+树组织的记录文件中记录的增删改查就要极大复杂

化日志写入过程。相比定长记录文件,对可变长记录的增删改查又是another story。

还有元数据管理子系统,记录(索引)子系

统。以上这些组成了一个存储引擎。题主还想要的额外的东西分别是: SQL lexer, SQL parser, SQL planner, SQL

optimizer。以上又构成了一个SQL compiler。 最后再来个Server/Client Module

用来控制权限,提供API,估计就差不多了。

对外数据模型为关系型数据库,内部的实现主要分成两大类,一类是disk-based,比如mysql,postgres,一类是memory based,后者包括MemSQL,SAP HAHA,OceanBase。看题目的意思指的是前者。判世这里说一个disk-based的关系型数据库涉及多少东西。

上世纪70/80年代内存不大,数据不能都放在内存里,大部分数据都存在磁盘上,读数据也需要从磁盘读,然而读写磁盘太慢了,所以就在内存里做了一个buffer pool,将已经读过的数据缓存到buffer pool中,写的时候也是写到buffer pool中就返回,buffer pool的功能就是管理数据在磁盘和内存的移动。在buffer pool中数据的管理单位是page。page大小一般几十KB。一般都可以配置。如果buffer pool中掘贺肢没有空闲的page,就需要将某一个page提出buffer pool,如果它是dirty page,就需要flush到磁盘,这里又需要一个LRU算法。一个page包含多条记录,page的格式需要设计用来支持变长字段。如果这时宕机了,buffer pool中的数据就丢了。这就需要REDO log,将对数据的修改先写到redo log中,然后写buffer pool,然后返回给客户端,随后,buffer pool中的dirty page会被刷到数据文件中(NO FORCE)。那么重启的时候,数据就能从redo log中恢复。REDO log还没刷完就刷数据到磁盘可以加快写入速度,缺点就是恢复的时候需要回放UNDO log,回滚一些还没有提交的事务的修改。写log又分为逻辑log和物理log,还有物理逻辑log。简单说逻辑log就是记录操作,比如将某个值从1改成2.而物理log记录具体到record的位置,例如某个page的某个record的某个field,原来的值是多少,新值是多少等。逻辑log的问题是并况下不太好恢复成一致。物理log对于某些操作比如create table又过于琐碎,所以一般数据库都采用混合的方式。为了跟踪系统中各种操作的顺序,这就需要为log分配id,记做LSN(log sequence number)。系统中记录各种LSN,比如pageLSN, flushedLSN等等。为了加快宕机恢复速度,需要定期写checkpoint,checkpoint就是一个LSN。

以上ACID里的C和D有关。下面说A和I,即原子性和隔离性。

这两个性质通过concurrency control来保证。隔离级别有很多种,最开始有4种,从低到高read uncommitted, read committed, repeatable read, serializable。serializable就是多个事务并发执行的结果和某种顺序执行事务的结果相同。除了serializable,其他都有各种问题。比如repeatable read有幻读问题(phantom),避免幻读需要gap lock。read committed有幻读和不可重复读问题。后来又多了一些隔离级别,比如snapshot isolation,snapshot isolation也有write skew问题。早期,并发控制协议大多是基于两阶段锁来做的(2PL),所以早拍吵期只有前面提到的四种隔离级别,后来,又出现一类并发控制协议,统称为Timestamp Ordering,所以又多了snapshot isolation等隔离级别。关于隔离级别,可以看看这篇论文

。2PL需要处理deadlock的问题。

Timestamp Ordering大体的思想就是认为事务之间冲突不大,不需要加锁,只在commit的时候check是否有冲突。属于一种乐观锁。

Timestamp Ordering具体来说包括多种,最常见的MVCC就是这类,还有一类叫做OCC(optimistic concurrency control)。MVCC就是对于事务的每次更新都产生新的版本,使用时间戳做版本号。读的时候可以读指定版本或者读最新的版本。几乎主流数据库都支持MVCC,因为MVCC读写互相不阻塞,读性能高。MySQL的回滚段就是用来保存老的版本。MVCC需要有后台线程来做不再需要的版本的回收工作。Postgres的vacuum就是做这事的。OCC和MVCC的区别是,OCC协议中,事务的修改保存在私有空间(比如客户端),commit的时候再去检测冲突,通常的做法是事务开始时看一下自己要修改的数据的最后一次修改的时间戳,提交的时候去check是否这个时间戳变大了,如果是,说明被别人改过了,冲突。冲突后可以回滚或者重试。

上面这些搞定了就实现了数据库的核心,然后为了性能,需要index,通常有两种,一种支持顺序扫描B+Tree,还有一种是Hash Index。单条读适合用Hash Index,O(1)时间复杂度,顺序扫描只适合用B+Tree,O(logN)复杂度。然后,有些查询只需要扫描索引就能得到结果,有些查询直接扫描数据表就能得到结果,有些查询可以走二级索引,通过二级索引找到数据表然后得到结果。。具体用哪种方式就是优化器的事了。

再外围一些,关系型数据库自然需要支持SQL了,由SQL变成最后可以执行的物理执行计划中间又有很多步,首先SQL通过词法语法分析生成抽象语法树,然后planner基于这棵树生成逻辑执行计划,逻辑执行计划的生成通常涉及到等价谓词重写,子查询消除等逻辑层面的优化技术,优化的目的当然是性能。比如等价谓词重写,用大于小于谓词消除like,between .. and..等不能利用索引的谓词。下一步是逻辑执行计划生成物理执行计划,物理执行计划树每个节点是一个operator,operator的执行就是实实在在的操作,比如扫表的operator,filter opertor。一个逻辑执行计划通常可以有多个物理执行对应,选择哪个就涉及到物理执行计划优化,这里涉及到经典的cost model,综合考虑内存,CPU, I/O,网络等。最典型的,三表join,从左到右还是右到左,使用hash join,还是sort merge join等。

如何自己实现一个关系型数据库

先写一个并发控制子系统。里面要提供各种各样的闩锁。包括具有不同相容性矩阵的,有优先队列或者没有的,能指数后退或者不能的,全局可追踪的或者不可追踪的,等等等等。

后写一个存储管理子系统。在这里你可以决定你的数据库的外存布局。比如一个表可不可以分开几个文件存,有没有区的概念,有没有段的概念,有没有表空间的概

念,它们之中谁是定长的,谁是可变长的,谁是空间申请单位,谁是空间调度单位。决定好了开始设计页区段表空间格式,它们的描述符格式,然后用页头,页记

录,页尾有的没的串一起。设计好了开始决定这个子系统有哪些内存对象,至少要有一个存储管理器用来初始化,分配或者调度存储单元,至少还要提供一堆方法来

决定怎么把二进制数据变成有意义的数据,比如读一个ushort, 写一个uint64等等。

之后就要开始写一个缓冲区管理子系统(假设

你做的不是一个内存数据库)。先弄明白什么是一个谈激block,一个page,

一个frame。这些都是你的类。然后写一个缓冲池,再写一个缓冲区管理器。缓冲池规定数据在内存上的布局,缓冲区管理器就是这个系统的接口了,可以回应

一个页的申请,并实现你最心仪的页替换策略。

再之后要写一个日志系统。先想好你是要用shadow

page日志啊,还是ARIES算法日志啊。假设用后者,于是你就失去了强制写,并采用偷帧的技术。这样你要设计redo日志的格式,并使你的日志记录种

类可扩展,因为不一定什么时候你就会需要一种新的日志记录。如果想让你的系统更稳健含哪袜,看看需不需要组日志(一组日志记录要么都重做要么都不重做)。如果想

让你的系统更高效,看看需不需要mvcc。要的话还得再加入undo日志,并设计格式。下面你要设计日志记录粒度。全物理日志?全逻辑日志?物理逻辑日

志。总之,逻辑的成分越多,系统设计越复杂(比如糟糕的部分写怎么处理)。最后跟存储管理系统要个地方物化日缓好志,再管缓冲区管理系统要个地方用来调度日志

页。

接下来要写一个锁系统。先想好你的系统是表级锁还是页级锁还是行级锁。前两个最自然,直接用fix

number什么的就搞定,最后一个你要有用来表示行锁的额外数据结构。每个行一个锁实例?每个页共用一坨锁实例?之后去这个锁表,用来统一申请释放锁。

最后再决定如何解决死锁,超时抛出异常?依赖图分析?

再接下来要写一个事务子系统。它无非就是提供了一些方法确保各种操作正确地使用了二

阶段锁,正确地写了日志,正确地回滚。但是这个系统的架构由”各种操作”的多样性决定。相比堆文件,对b+树组织的记录文件中记录的增删改查就要极大复杂

化日志写入过程。相比定长记录文件,对可变长记录的增删改查又是another story。

还有元数据管理子系统,记录(索引)子系

统。以上这些组成了一个存储引擎。题主还想要的额外的东西分别是: SQL lexer, SQL parser, SQL planner, SQL

optimizer。以上又构成了一个SQL compiler。 最后再来个Server/Client Module

用来控制权限,提供API,估计就差不多了。

关于数据库布局的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » 如何优化数据库布局? (数据库布局)