DataGrip设置时区
索引
- 索引中记录了表中一列或多列的值与其物理位置之间的对应关系,可以通过索引快速定位到需要查询的内容。
- 创建索引可以加快对表中记录的查找或排序。
- 创建索引的代价:
- 增加了数据库的存储空间。
- 在插入和删除数据时要花费较多的时间,因为索引也要随之更新。
事务特性
- 原子性(Atomicity):事务中的操作要么全部成功,要么全部失败
- 一致性(Consistency):一个事务执行之前和执行之后都必须处于一致性状态。
- 举例:假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
- 隔离性(Isolation):对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行,分为不同的隔离级别。
- 持久性(Durability):一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的。
事务隔离级别:
三种问题
- 脏读:一个事务在其自己的处理过程里读取了另一个未提交的事务中写入的数据。
- 不可重复读:事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
- 幻读:事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
四种隔离级别
- Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
- Repeatable read (可重复读):可避免脏读、不可重复读的发生。
- Read committed (读已提交):可避免脏读的发生。
- Read uncommitted (读未提交):最低级别,任何情况都无法保证。
PostgreSQL中的事务隔离
- 默认是读已提交。
- 当一个事务运行在这个隔离级别时,select查询只能看到查询开始之前已提交的数据,而无法看到未提交的数据或在查询执行期间其他事务已提交的数据。
- 事务中的select查询可以看到自己所在事务中前面尚未提交的更新结果。
- 在同一个事务中的两个相邻的select命令可能看到不同的快照,因为可能在两个select查询操作之前有其他事务提交。
- 仅支持读已提价和可串行化这两种事务隔离机制。
多版本并发控制(MVCC)
控制并发读写旧的方法是使用读写锁,即读的时候不允许写,写的时候不允许读。导致读写不能并发。
- 实现MVCC的两种方法:
- 写新数据时,把旧数据移动一个单独的地方,如回滚段中,其他人读数据时,从回滚段中把旧的数据读出来。
- 写新数据时,旧数据不删除,而是把新数据插入。
MVCC用到的系统字段
为了实现MVCC,每张表上都添加了四个系统字段:xmin、xmax、cmin、cmax
-
xmin:标记插入该行数据的事务ID。
-
xmax:标记删除该行数据的事务ID。
- 新插入一行时,将新插入行的xmin填写为当前的事务ID,xmax填0。
- 修改某一行时,实际上是新插入一行,旧行上的xmin不变,旧行上的xmax改为当前事务ID,新行上的xmin填为当前事务ID,新行上的xmax填为0。
- 删除一行时,把被删除行上的xmax填为当前事务ID。
- 关于事务ID:是一个32bit数字,从3开始递增到最大值,之后再从3开始。
-
cmin:事务内部插入类操作的命令ID。
-
cmax:事务内部删除类操作的命令ID。
- 每个命令使用事务内一个全局命令标识计数器的当前值作为当前命令标识。
- 事务开始时,命令标识计数器被置为初值0。
- 执行更新性的命令(insert、update、delete、select…for update)时,在SQL执行后命令标识计数器加1。
- 当命令标识计数器经过不断累加又回到初值0时,报错“cannot have more than 2^32-1 commands in a transaction”,即一个事务中的命令的个数最多为2^32-1个。
事务状态
- PostgreSQL把事务状态记录在commit log中。
- 0x00表示事务正在进行中。
- 0x01表示事务已经提交。
- 0x02表示事务已经回滚。
- 0x03表示子事务已提交。
PostgreSQL中的MVCC
- 当两个事务同时访问记录时,通过参考xmin和xmax的标记可判断记录的版本,然后根据版本号与自己当前的事务标识进行比较,确定自己的数据权限。
- 当删除数据时,记录并没有从数据块中删除,空间也没有立即释放。PostgreSQL通过运行vaccum进程来回收之前的存储空间。默认PostgreSQL数据库中的autovacuum是打开的,也就是说当一个表的更新达到一定数量时,autovacuum自动回收空间。
- 在PostgreSQL中,并不会在事务提交时把这些数据标记成有效,在事务回滚时标记为无效,如果事务提交或回滚时再次标记了数据,那这些数据就有可能会被刷新到磁盘中,而再次导致另一次I/O,从而降低了性能。PostgreSQL是通过记录事务的状态到commit log中来实现的。
PostgreSQL多版本的优劣分析
- 相对于InnoDB和Oracle,优势在于:
- 事务回滚可以立即完成,无论事务进行了多少操作。
- 数据可以进行很多更新,不必像Oracle和InnoDB那样需要经常保证回滚段不会被用完。
- 劣势在于:
- 旧版本数据需要清理,就是vacuum。
- 旧版本的数据会导致查询更慢一些。
PostgreSQL的核心架构
- Postmaster 主进程
- 它是整个数据库实例的总控进程,负责启动和关闭该数据库实例。
- 它是第一个PostgreSQL进程,此主进程还会fork出其他子进程,并管理他们。
- 当用户和PostgreSQL建立连接时,首先是和Postmaster进程建立连接。首先,客户端会发出身份验证的信息给Postmaster进程,Postmaster进程根据消息中的信息进行身份验证判断,如果验证通过,它会fork出一个子进程为这个连接服务。
PostgreSQL是进程架构模型,MySQL是线程架构模型。
- SysLogger 系统日志进程
- 它从Postmaster主进程、所有的服务进程以及其他辅助进程收集所有的stderr输出,并将这些输出写入到日志文件中。
- BgWriter 后台写进程
- 为了提高插入、删除和更新数据的性能,当往数据库中插入或者更新数据时,并不会马上把数据持久化到数据文件中。
- 该辅助进程可以周期性的把内存中的脏数据刷新到磁盘中。
- WalWriter 预写式日志进程
- WAL是write ahead log的缩写,WAL log也称为xlog,
- 预写式日志的概念是在修改数据之前,必须把这些修改操作记录到磁盘中,这样后面更新实际数据时,就不需要实时的把数据持久化到文件中了。即使机器突然宕机或者数据库异常退出, 导致一部分内存中的脏数据没有及时的刷新到文件中,在数据库重启后,通过读取WAL日志,并把最后一部分WAL日志重新执行一遍,就能恢复到宕机时的状态了。
- PgArch 归档进程
- WAL日志文件会被循环使用,也就是说WAL日志会被覆盖,PgArch进程会在覆盖前把WAL日志备份出来。
- AutoVacuum 自动清理进程
- 执行delete操作时,旧的数据并不会立即被删除,在更新数据时,也不会在旧的数据上做更新,而是新生成一行数据。旧的数据只是被标识为删除状态,在没有并发的其他事务读到这些旧数据时,它们才会被清除掉。清楚的工作就是由AutoVacuum进程进行的。
- PgStat 统计数据收集进程
- 它主要做数据的统计收集工作。收集的信息主要用于查询优化时的代价估算。统计的数据有对一个表或索引进行的插入、删除、更新操作,磁盘块读写的次数以及行的读次数等。