计算机必备小知识【数据库、内存】

1 mysql数存储类型(database)

1.1 char与varcha区别

  • char的存储空间是固定长度;varchar是可变长
  • varchar会比char多1至2个字节来存放数据的长度

1.2 varchar存储

①varchar能存多少汉字、数字呢?

具体需要看数据库版本和编码(以MySQL为例)

  • 4.0版本以下,varchar(100),指100字节,如果存放UTF8汉字,只能存放33个(每个汉字3字节)
  • 5.0版本以上,varchar(100),指100字符,无论存放数字、字母还是UTF8汉字(每个汉字3字节),都可以存放100个
UTF8编码中,一个汉字(数字)占3字节
GBK编码中,一个汉字(数字)占2字节

a、A、中、+、*、の…均表示一个字符;
一般 utf-8 编码下,一个汉字 字符 占用 3 个 字节;数字属于汉字,和汉字占用一样字节。
一般 gbk 编码下,一个汉字 字符 占用 2 个 字节;

1.3 mysql各类型所占空间

数字类型:

类型

存储量

TINYINT

1字节

SMALLINT

2字节

MEDIUMINT

3字节

INT

4字节

INTEGER

4字节

BIGINT

8字节

FLOAT(X)

4 如果 X < = 24 或 8 如果 25 < = X < = 53

FLOAT

4 个字节

DOUBLE

8 个字节

DOUBLE PRECISION

8 个字节

REAL

8 个字节

DECIMAL(M,D)

M字节(D+2 , 如果M < D)

NUMERIC(M,D)

M字节(D+2 , 如果M < D)

日期和时间类型:

类型

所占空间

DATE

3 个字节

DATETIME

8 个字节

TIMESTAMP

4 个字节

TIME

3 个字节

YEAR

1 字节

拓展:text与blob的区别在于:text不能存储图片。blob是二进制流,text是非二进制。
mysql 的二进制数据类型 BINARY, VARBINARY, BLOB 都没有字符集的概念。

参考文章:

2 估算内存

2.1 单位换算关系

基本单位换算关系:

11B(Byte 字节) = 8bit(位)
21KB = 1024B
31MB = 1024KB
41GB = 1024MB
51TB = 1024GB

Java对象占用内存:

数据类型

占用内存(单位为Byte)

boolean

1

byte

1

short

2

char

2

int

4

float

4

long

8

double

8

注意:Java中使用Unicode字符,所有的字符均以两个字节存储。
【char无论是中英文数字都占用两个字节】

2.2 对象内存布局(Java)

  • 引用类型:平时我们存储对象就是存储的一个指针,指向堆内存中的对象。指针默认情况占4字节(开启了指针压缩),如果没有开启,则占用8字节
  • 在HotSpot虚拟机中,对象在内存中存储的布局可以分为三个区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。

①对象头

在对象头中存储了两部分数据

运行时数据:存储了对象自身运行时的数据,例如哈希码、GC分代的年龄、锁状态标志、线程持有的锁、偏向线程ID等等。这部分数据在32位和64位的虚拟机中分别为32bit和64bit
类型指针:对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。如果对象是一个Java数组的话,那么对象头中还必须有一块用于记录数组长度的数据(占用4个字节)。所以这是一个指针,默认JVM对指针进行了压缩,用4个字节存储。

我们以虚拟机为64位的机器为例,那么对象头占用的内存是8(运行时数据)+4(类型指针)=12Byte。如果是数组的话那么就是16Byte

②实例数据

实例数据中也拥有两部分数据,一部分是基本类型数据,一部分是引用指针。这两部分数据我们在上面已经讲了。具体占用多少内存我们需要结合具体的对象继续分析,下面我们会有具体的分析。

从父类中继承下来的变量也是需要进行计算的

③对齐填充

对齐填充并不是必然存在的,也没有特别的含义。它仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是对象的大小必须是8字节的整数倍。而如果对象头加上实例数据不是8的整数倍的话那么就会通过对其填充进行补全。

几百万数据放到内存中会把内存撑爆吗?这时候你可以通过自己的计算得到。最终我们那个需求经过我算出来其实占用内存量几百兆,对于4个G的堆内存来说其实远远还没达到撑爆的地步。

详细说明:

2.4 1000W条数据占用mysql磁盘(大约18G)

结论:(8+2000+8+4) * 10000000 = 20200000000 字节 == 18G

①设计一张表

CREATE TABLE `table_name` (
 
id bigint(20) not null auto_increment,
 
detail varchar(2000),
 
createtime  datetime,
 
validity int default '0',
 
primary key (id)
 
);

②每个字段所占字节数

bigint 8字节 
 
varchar 2000 字节 
 
datetime  8字节 
 
validity 4字节

算乘法计算占用磁盘:
(8+2000+8+4) * 10000000 = 20200000000 字节 == 18G
因此,我们在设计数据库的时候,要采用最小类型的原则

但是该计算公式仅为简单计算;mysql索引和表分离本身是分离,有时索引占用的磁盘空间可能比表占用的磁盘空间都要大!!

查询sql:

  1. 库空间以及索引空间大小:
select TABLE_SCHEMA, concat(truncate(sum(data_length)/1024/1024,2),' MB') as data_size,
    concat(truncate(sum(index_length)/1024/1024,2),'MB') as index_size
     from information_schema.tables
     group by TABLE_SCHEMA
     order by data_length desc;
  1. 查询某个数据库内每张表的大小:
concat(truncate(index_length/1024/1024,2),' MB') as index_size
 from information_schema.tables where TABLE_SCHEMA = 'metadata'
 group by TABLE_NAME
 order by data_length desc;
  1. 查看数据库中所有表的信息
SELECT CONCAT(table_schema,'.',table_name) AS 'Table Name', 
CONCAT(truncate(table_rows/1000000,2),'M') AS 'Number of Rows', 
CONCAT(truncate(data_length/(1024*1024*1024),2),'G') AS 'Data Size', 
CONCAT(truncate(index_length/(1024*1024*1024),2),'G') AS 'Index Size' , 
CONCAT(truncate((data_length+index_length)/(1024*1024*1024),2),'G') AS  'Total' FROM information_schema.TABLES WHERE table_schema LIKE 'metadata';