列顺序占用存储大小的影响 in Oracle、MySQL、PostGreSQL

列顺序占用存储大小的影响 in Oracle、MySQL、PostGreSQL

image-20230916215633503

在创建表时,如果相同的列类型,不同表列的顺序是否会影响数据库占用空间大小?使用oracle、mysql或postgresql是不是相同的表现呢? 不是的Postgresql近期发现空间使用会因为columns的顺序而占用不同的大小,当然也和实际的数据有关,简单的测试。

Oracle

SQL> CREATE TABLE t_test ( i1 int,
i2 int,
i3 int,
v1 varchar(100),
v2 varchar(100),
v3 varchar(100)
  7  );

Table created.

INSERT INTO t_test SELECT 10, 20, 30,
'abcd', 'abcd', 'abcd'
  3  FROM dual connect by rownum<=10000; 10000 rows created.

SQL> select BYTES from dba_segments where segment_name='T_TEST';

     BYTES
----------
    393216

SQL> SELECT dbms_xplan.FORMAT_SIZE(BYTES) SEG_SIZE from dba_segments where segment_name='T_TEST';

SEG_SIZE
------------------------------
384K

SQL> DROP TABLE T_TEST;
Table dropped.

SQL> CREATE TABLE t_test ( v1 varchar(100),
i1 int,
v2 varchar(100),
i2 int,
v3 varchar(100),
i3 int
  7  );

Table created.

SQL> INSERT INTO t_test SELECT 'abcd', 10, 'abcd',
20, 'abcd', 30
  3  FROM dual connect by rownum<=10000; SQL> select BYTES from dba_segments where segment_name='T_TEST';

     BYTES
----------
    393216

Note:
在ORACLE数据库中TABLE COLUMN顺序打乱后, 表段大小一致。

MySQL

mysql> create table t_test( i1 int,i2 int, i3 int,v1 varchar(100),v2 varchar(100),v3 varchar(100));
Query OK, 0 rows affected (0.09 sec)

mysql> DELIMITER $$
mysql> CREATE PROCEDURE LoadCal()
    -> BEGIN
    ->     declare n int default 1;
    ->     declare MAX int default 10001;
    ->     while n < MAX do ->         insert into t_test select 10,20,30,'abcd','abcd','abcd';
    ->         set n = n + 1;
    ->     end while;
    -> END$$
Query OK, 0 rows affected (0.02 sec)

mysql> DELIMITER ;
mysql> select count(*) from t_test;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

mysql> call LoadCal();
Query OK, 1 row affected (1 min 17.73 sec)

mysql> select count(*) from t_test;
+----------+
| count(*) |
+----------+
|    10000 |
+----------+
1 row in set (0.05 sec)

mysql> SELECT TABLE_NAME  ,
    -> CONCAT(ROUND((DATA_LENGTH)/1024,2),'KB') AS'total'
    ->  FROM information_schema.TABLES WHERE TABLE_NAME='t_test';
+------------+-----------+
| TABLE_NAME | total     |
+------------+-----------+
| t_test     | 1552.00KB |
+------------+-----------+
1 row in set (0.00 sec)

mysql> drop table t_test;
Query OK, 0 rows affected (0.04 sec)

mysql> create table t_test(  v1 varchar(100),i1 int, v2 varchar(100),i2 int,v3 varchar(100),i3 int);
Query OK, 0 rows affected (0.05 sec)

mysql> drop procedure LoadCal;
Query OK, 0 rows affected (0.03 sec)

mysql> DELIMITER $$
mysql> CREATE PROCEDURE LoadCal()
    -> BEGIN
    ->     declare n int default 1;
    ->     declare MAX int default 10001;
    ->     while n < MAX do ->         insert into t_test select 'abcd',10,'abcd',20,'abcd',30 ;
    ->         set n = n + 1;
    ->     end while;
    -> END$$
Query OK, 0 rows affected (0.02 sec)

mysql> DELIMITER ;
mysql> call LoadCal;
Query OK, 1 row affected (1 min 15.33 sec)

mysql> SELECT TABLE_NAME  ,
    -> CONCAT(ROUND((DATA_LENGTH)/1024,2),'KB') AS'total'
    ->  FROM information_schema.TABLES WHERE TABLE_NAME='t_test';
+------------+-----------+
| TABLE_NAME | total     |
+------------+-----------+
| t_test     | 1552.00KB |
+------------+-----------+
1 row in set (0.00 sec)

Note:
MySQL数据库,表列不同的顺序,表所占用空间大小也是一致。

PostGreSQL

anbob=# CREATE TABLE t_test ( i1 int,
anbob(# i2 int,
anbob(# i3 int,
anbob(# v1 varchar(100),
anbob(# v2 varchar(100),
anbob(# v3 varchar(100)
anbob(# );
CREATE TABLE
anbob=# INSERT INTO t_test SELECT 10, 20, 30,
anbob-# 'abcd', 'abcd', 'abcd'
anbob-# FROM generate_series(1, 10000);
INSERT 0 10000
anbob=# select pg_relation_size('t_test');
 pg_relation_size
------------------
           606208
(1 row)

anbob=# select pg_size_pretty( pg_relation_size('t_test'));
 pg_size_pretty
----------------
 592 kB
(1 row)

anbob=# drop table t_test;
DROP TABLE
anbob=# CREATE TABLE t_test ( v1 varchar(100),
anbob(# i1 int,
anbob(# v2 varchar(100),
anbob(# i2 int,
anbob(# v3 varchar(100),
anbob(# i3 int
anbob(# );
CREATE TABLE
anbob=# INSERT INTO t_test SELECT 'abcd', 10, 'abcd',
anbob-# 20, 'abcd', 30
anbob-# FROM generate_series(1, 10000);
INSERT 0 10000
anbob=# select pg_size_pretty( pg_relation_size('t_test'));
 pg_size_pretty
----------------
 672 kB
(1 row)

Note:

在PostgreSQL数据中,尽管表中的数据完全相同,但该表已显着增长。

这个问题的原因称为alignment(对齐)。

PostgreSQL tuple内部有ALIGN机制,因此字段顺序也有讲究,选择不好,可能因为ALIGN导致空间放大, 理论如下:

如果一个字段没有以CPU word-size的倍数开始,那么 CPU 就会遇到困难,在代码src/backend/access/common/heaptuple.c。

因此,PostgreSQL 会相应地在物理上对齐数据。 这里最重要的一点是,将具有相似数据类型的列彼此相邻分组是有意义的。

当然,结果和潜在的大小差异在很大程度上取决于内容。 如果在此示例中使用“abc”而不是“abcd”,则结果不会显示任何差异;

weejar=#  select pg_column_size(row(int4 '10',varchar 'abc',int4 '10',varchar 'abc'));
 pg_column_size
----------------
             40
-- 24+4+4+4+4

weejar=#   select pg_column_size(row(int4 '10',int4 '10',varchar 'abc',varchar 'abc'));
 pg_column_size
----------------
             40

typalign char

typalign is the alignment required when storing a value of this type. It applies to storage on disk as well as most representations of the value inside PostgreSQL. When multiple values are stored consecutively, such as in the representation of a complete row on disk, padding is inserted before a datum of this type so that it begins on the specified boundary. The alignment reference is the beginning of the first datum in the sequence. Possible values are:

  • c = char alignment, i.e., no alignment needed.
  • s = short alignment (2 bytes on most machines).
  • i = int alignment (4 bytes on most machines).
  • d = double alignment (8 bytes on many machines, but by no means all).
weejar=# select pg_column_size(row(varchar 'abc'));
 pg_column_size
----------------
             28
weejar=#   select pg_column_size(row(int4 '10'));
 pg_column_size
----------------
             28
weejar=# select pg_column_size(row(varchar 'abcd'));
 pg_column_size
----------------
             29
weejar=# select pg_column_size(row(varchar 'abcd',int4 '10'));
 pg_column_size
----------------
             36

Note:
36= header + “abcd” 5 取4倍数为8+int4 4
= 24+4+[1+(3补齐)}+4

在C或Go Lang开发对象中同样存在该设计,如GO

image-20230916220824213

查看这个表的对齐规则

SELECT a.attname, t.typname, t.typalign, t.typlen
FROM pg_class c
JOIN pg_attribute a ON (a.attrelid = c.oid)
JOIN pg_type t ON (t.oid = a.atttypid)
WHERE c.relname = 'xxx'
AND a.attnum >= 0
ORDER BY a.attnum;

Summary

测试发现目前只有postgresql会因为补齐问题,在相同数据不同的列顺序时会产生不同的空间大小,而oracle和MySQL不存在,所以在PostgreSQL中注意列顺序,同时在opengauss系也和PG相同的表现。

by the way, 对于10000行相同的数据也可以看出三个数据库的磁盘空间耗费排列 MySQL (1500K)> PostgreSQL (600K) > Oracle (300K)

<think>我们被要求总结MySQL的主要特点。根据提供的引用内容,我们可以从以下几个方面进行总结:1.**轻量级与易用性**:引用[2]提到MySQL是开源的轻量级数据库,安装方便快捷,维护也比较方便,追求稳定的性能和易用性。这使得它在开源数据库中比较流行,尤其适用于互联网公司。2.**关系型数据库管理系统**:引用[2]指出MySQL是关系型数据库管理系统(RDBMS)之一,使用结构化查询语言(SQL)进行数据管理。3.**功能特点**:-引用[1]提到MySQL在某些高级功能上(如复杂查询优化、存储过程和触发器)可能不如其他数据库系统(如PostgreSQL)强大。-引用[3]提到了MySQL的索引特性,包括聚集索引和非聚集索引。聚集索引(如主键)的插入是顺序的,速度很快;而非聚集索引(如普通索引)的插入可能是离散的,性能相对较低。4.**并发与性能**:-引用[1]指出在高并发写入场景中,MySQL可能会遇到性能瓶颈,尤其是在使用MyISAM存储引擎时(因为MyISAM是表级锁,而InnoDB支持行级锁,但引用中没有明确提到InnoDB)。-引用[3]通过索引的插入性能说明了B+树索引的特性。5.**分布式支持**:引用[1]提到尽管MySQL支持集群,但在原生的分布式处理和横向扩展方面,不如一些NoSQL数据库或其他分布式数据库系统。6.**开源与流行性**:引用[2]强调MySQL是开源的,属于Oracle旗下,在开源数据库中非常流行。我们可以将这些特点归纳为几个核心点,并适当引用原文。注意:引用[3]主要讨论索引特性,我们可以将其归入“存储引擎与索引”部分。总结如下:---###MySQL主要特点总结####一、**轻量级与易用性**[^2]-**轻量级设计**:核心库体积小,安装部署便捷,适合快速搭建应用环境。-**维护方便**:作为开源数据库,社区支持完善,日常运维管理简单高效。-**适用场景**:广泛应用于互联网公司,尤其适合对性能和稳定性要求较高的场景。####二、**关系型数据库特性**[^2]-**结构化查询语言(SQL)**:支持标准的SQL语法,实现数据定义、操作与控制。-**ACID事务支持**:通过InnoDB等存储引擎提供事务安全性(引用未直接提及,但属于MySQL重要特性,可补充说明,但若无引用则避免添加)。-**数据关系模型**:基于表结构组织数据,支持主键、外键等关系约束。####三、**存储引擎与索引机制**[^3]-**多存储引擎支持**:如MyISAM(侧重读性能)、InnoDB(支持事务与行级锁)等(引用未明确举,但引用[1]提到了MyISAM)。-**索引优化**:-**聚集索引**:主键索引实现数据物理顺序存储,提升顺序插入效率[^3]。-**非聚集索引**:普通索引需离散访问索引页,插入性能较低(受B+树结构影响)[^3]。####四、**功能与性能局限**[^1]-**高级功能不足**:在复杂查询优化、存储过程/触发器支持上弱于PostgreSQL数据库。-**并发瓶颈**:高并发写入时MyISAM引擎易出现锁竞争问题(表级锁限制)[^1]。-**分布式短板**:原生横向扩展能力有限,需依赖中间件实现分库分表。####五、**开源与生态优势**[^2]-**开源免费**:遵循GPL许可,社区版本可免费商用。-**生态丰富**:拥有完善的工具链(如MySQLWorkbench)及多语言驱动支持。```mermaidgraphLRA[轻量易用]-->B[关系型数据库]B-->C[存储引擎灵活]C-->D[功能局限]D-->E[开源生态]```---###核心特点对比|特点|优势|局限性||---------------------|-----------------------------------|---------------------------------||**轻量级**|安装快、运维简单|功能扩展性受限[^1]||**关系模型**|数据一致性高,SQL通用性强|复杂查询性能弱于NoSQL[^1]||**多存储引擎**|适配不同场景(读优化/事务支持)|MyISAM高并发写入性能低[^1]||**开源生态**|社区活跃,工具链完善|企业级支持需商业版[^2]|>**总结**:MySQL凭借**轻量易用**、**开源免费**和**成熟的关系型数据管理能力**,成为Web应用的主流数据库;但在高并发写入、分布式扩展及高级功能上需针对性优化[^1][^2]。---§§相关问题§§1.MyISAM和InnoDB存储引擎的主要区别是什么?2.MySQL如何通过分库分表解决分布式扩展问题?3.B+树索引结构如何影响MySQL的查询与写入性能?[^3]4.相比PostgreSQLMySQL在哪些高级功能上存在不足?[^1]</think>### MySQL 主要特点总结 #### 一、**轻量级与易用性**[^2] - **体积小巧**:核心系统设计轻量化,安装部署便捷,资源占用低。 - **运维简单**:配置与管理门槛低,适合快速搭建开发环境。 - **开源免费**:遵循 GPL 许可,社区版可免费商用,降低企业成本。 #### 二、**关系型数据库核心特性**[^2] - **结构化数据管理**:基于表结构存储数据,支持主键、外键等关系约束。 - **标准 SQL 支持**:兼容 ANSI SQL 语法,提供数据定义(DDL)、操作(DML)和控制(DCL)能力。 - **ACID 事务保障**:通过 InnoDB 等引擎实现原子性、一致性、隔离性、持久性(需补充引擎特性)。 #### 三、**存储引擎灵活性**[^1][^3] - **多引擎架构**:支持 MyISAM(读优化)、InnoDB(事务安全)等引擎,适配不同场景。 - **索引优化机制**: - **聚集索引**:主键索引实现数据物理顺序存储,提升顺序插入效率[^3]。 - **非聚集索引**:普通索引离散存储,查询快但插入需额外维护 B+ 树结构[^3]。 #### 四、**性能与扩展性局限**[^1] - **高并发瓶颈**:MyISAM 引擎的表级锁在高并发写入时易出现竞争问题。 - **分布式短板**:原生横向扩展能力弱于 NoSQL 数据库,需依赖分库分表中间件。 - **高级功能不足**:复杂查询优化、存储过程/触发器支持弱于 PostgreSQL数据库。 #### 五、**典型应用场景**[^2] - **Web 应用**:凭借轻量化和易维护性,成为 LAMP/LEMP 技术栈的核心组件。 - **中小型企业系统**:适用于电商、内容管理等对事务一致性要求较高的场景。 ```mermaid graph TD A[轻量易用] --> B[关系型数据管理] B --> C[多存储引擎] C --> D[读写性能优化] D --> E[扩展性局限] ``` --- ### 核心特点对比 | 特点 | 优势 | 局限性 | |---------------------|-----------------------------------|---------------------------------| | **轻量级** | 部署快、资源消耗低 | 复杂功能支持弱[^1] | | **多存储引擎** | 灵活适配读写场景 | MyISAM 高并发写入性能低[^1] | | **索引机制** | B+ 树加速查询 | 非聚集索引插入效率低[^3
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值