计算机必备小知识【数据库、内存】
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 都没有字符集的概念。
参考文章:https://www.cnblogs.com/zhuyeshen/p/11642211.html
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的堆内存来说其实远远还没达到撑爆的地步。
详细说明:https://juejin.cn/post/6844904025524011016
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:
- 库空间以及索引空间大小:
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;
- 查询某个数据库内每张表的大小:
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;
- 查看数据库中所有表的信息
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';
参考文章:
https://blog.csdn.net/u010235716/article/details/86629756