这里写自定义目录标题
MySQL基本介绍
SQL 是Structure Query Language(结构化查询语言)的缩写,它是使用关系模型的数据库应用语言。SQL的扩展语言有MySQL、SQL Service等。
基本架构
SQL 语句分类
SQL 语句主要可以划分为以下3 个类别:
- DDL(Data Definition Languages)语句
数据定义语言,这些语句定义了不同的数据段、数据库、表、列、索引等数据库对象的定义。常用的语句关键字主要包括create、drop、alter等。 - DML(Data Manipulation Language)语句
数据操纵语句,用于添加、删除、更新和查询数据库记录,并检查数据完整性,常用的语句关键字主要包括insert、delete、udpate 和select 等。 - DCL(Data Control Language)语句
数据控制语句,用于控制不同数据段直接的许可和访问级别的语句。这些语句定义了数据库、表、字段、用户的访问权限和安全级别。主要的语句关键字包括grant、revoke 等。
MySQL在线帮助文档
-
HELP contents 查看MySQL命令的使用。
help contents查看所有的类型。当需要具体到某个类的时候,可以使用HELP 类别名。eg:HELP ‘Data Type’ 查看所有的数据类型的使用方法。根据全部的一级一级的筛选查询自己想要的内容 -
SHOW VARIABLES
可以通过SHOW VARIABLES语句查看系统变量及其值。eg:SHOW VARIABLES like ‘%show%’。默认的级别是session,此外还有global, SHOW GLOBAL VARIABLES。session就是当前会话级别的查询,global就是全局级别。 -
SHOW STATUS
在MySQL中,我们可以使用SHOW STATUS指令语句来查看MySQL服务器的状态信息。当我们希望能够「按需查看」一部分状态信息。这个时候,我们可以在show status语句后加上对应的like子句。例如,我们想要查看当前MySQL启动后的运行时间,我们可以执行如下语句:show status like ‘%select%’。他也是有session级别和global级别的,使用方法同SHOW VARIABLES 一样。 -
select version() 查看SQL的版本号
select now() 查看当前时间
SQL的类型分类
整数类型
-
整数宽度
对于整型数据,MySQL还支持在类型名称后面的小括号内指定显示宽度,例如int(5)表示当数值宽度小于5位的时候在数字前面填满宽度,如果不显示指定宽度则默认为int(11)。设置了宽度限制后,如果插入大于宽度限制的值,会不会截断或者插不进去报错?答案是肯定的:不会对插入的数据有任何影响,还是按照类型的实际精度进行保存 -
UNSIGNED属性
所有的整数类型都有一个可选属性UNSIGNED(无符号),如果需要在字段里面保存非负数或者需要较大的上限值时,可以用此选项,它的取值范围是正常值的下限取0,上限取原值的2倍,例如,tinyint有符号范围是-128~+127,而无符号范围是0~255。。如果一个列指定为zerofill,则MySQL自动为该列添加UNSIGNED属性 -
AUTO_INCREMENT属性
整数类型还有一个属性:AUTO_INCREMENT。在需要产生唯一标识符或顺序值时, 可利用此属性,这个属性只用于整数类型。AUTO_INCREMENT 值一般从1 开始,每行增加1。 在插入NULL 到一个AUTO_INCREMENT 列时,MySQL 插入一个比该列中当前最大值大1 的 值。一个表中最多只能有一个AUTO_INCREMENT列。对于任何想要使用AUTO_INCREMENT 的 列,应该定义为NOT NULL,并定义为PRIMARY KEY 或定义为UNIQUE 键。
查看自增的信息show variables like '%increment%'
-
sql_mode使用
一、 有些时候在你添加数据的时候,明明会出现数据溢出的问题,却依然能正常的操作,只是数据却不是自己想要的。这个时候可以看一下sql_mode的设置。sql_mode的基本命令命令select @@sql_mode set @@sql_mode=TRADITIONAL。 参考
二、使用方法解决问题- 可以完成不同严格程度的数据校验,有效地保障数据准确性。
- 应用在不同数据库之间进行迁移时,则不需要对业务SQL 进行较大的修改。
- 在不同数据库之间进行数据迁移之前,通过设置SQL Mode 可以使MySQL上的数据更方便地迁移到目标数据库中。
小数类型
-
分类
MySQL 分为两种方式:浮点数和定点数。浮点数包括float(单精度)和double(双精度),而定点数则只有decimal一种表示。定点数在MySQL内部以字符串形式存放,比浮点数更精确,适合用来表示货币等精度高的数据。 -
使用
浮点数和定点数都可以用类型名称后加“(M,D)”的方式来进行表示,“(M,D)”表示该值一共显示M 位数字(整数位+小数位),其中D位位于小数点后面,M 和D 又称为精度和标度。
MySQL 保存值时进行四舍五入,因此如果在float(7,4)列内插入999.00009,近似结果是999.0001。值得注意的是,浮点数后面跟“(M,D)”的用法是非标准用法,如果要用于数据库的迁移,则最好不要这么使用 -
注意
float 和double在不指定精度时,默认会按照实际的精度(由实际的硬件和操作系统决定) 来显示,而decimal在不指定精度时,默认的整数位为10,默认的小数位为0。
BIT(位)类型
-
介绍
对于BIT(位)类型,用于存放位字段值,BIT(M)可以用来存放多位二进制数,M 范围从1~64,如果不写则默认为1位。 -
使用
对于位字段,如果直接使用SELECT命令看不到结果,可以用bin()(显示为二进制格式)或者hex()(显示为十六进制格式)函数进行读取
时间类型
- 分类
类型 | 字节 | 最小值 | 最大值 | 零值表示 |
---|---|---|---|---|
DATE | 4 | 1000-01-01 | 9999-12-31 | 0000-00-00 |
DATETIME | 8 | 1000-01-01 00:00:00 | 9999-12-31 23:59:59 | 0000-00-00 00:00:00 |
TIMESTAMP | 4 | 19700101080001 | 2038年的某个时刻 | 00000000000000 |
TIME | 3 | -838:59:59 | 838:59:59 | 00:00:00 |
YEAR | 1 | 1901 | 2155 | 0000 |
-
这些数据类型的主要区别如下:
- DATE来表示年月。
- DATETIME表示年月日时分秒
- TIME 来表示时分秒
- 通常使用TIMESTAMP经常插入或者更新日期为当前系统时间。TIMESTAMP 值返回后显示为“YYYY-MM-DD HH:MM:SS”格式的字符串,显示宽度固定为19个字符。如果想要获得数字值,应在TIMESTAMP列添加+0。
- YEAR表示年份,它比DATE占用更少的空间。YEAR有2位或4位格式的年。默认是4位格式。在4位格式中,允许的值是1901~2155 和0000。在2位格式中,允许的值是70~69,表示从1970~2069年。MySQL以YYYY 格式显示YEAR值。
-
使用
DATETIME和TIMESTAMP可以设置CURRENT_TIME默认值为当前系统时间。在添加当前时间时,使用函数now()。
insert into t1(id7) values(now());
alter table t1 modify `id5` timestamp NULL DEFAULT CURRENT_TIMESTAMP;
-
TIMESTAMP和DATETIEM区别
-
TIMESTAMP的插入和查询都受当地时区的影响,更能反应出实际的日期。而DATETIME则只能反应出插入时当地的时区,其他时区的人查看数据必然会有误差的。
-
TIMESTAMP占用的内存是是DATETIME的一半。TIMESTAMP存储的是从1970年1月1日午夜以来的秒数,占用4个字节,DATETIME存储的格式YYYYMMDDHHMMSS格式,占用8个字节。
-
案例解释:show variables like 'time_zone’当时的时区为SYSTEM,即东八区。时区改为东九区,添加数据,两个字段的属性如下
'id5' timestamp NULL DEFAULT CURRENT_TIMESTAMP, 'id6' datetime DEFAULT CURRENT_TIMESTAMP
此时两个时间是一致的,都是东九区的时间;然后将时区改为原先的东八区,发现id5时间又变成了东八区的时间,而id6还是原先的九区时间。 -
相关时区命令
-- 查看时区
show variables like 'time_zone';
-- 查看时区
select @@time_zone;
-- 修改时区
set time_zone='+9:00';
时区的值为“SYSTEM”,这个值默认是和主机的时区值一致的,因为我们在中国,这里的“SYSTEM”实际是东八区(+8:00)。
CHAR & VARCHAR
CHAR 和VARCHAR 很类似,都用来保存MySQL 中较短的字符串。两者的存储数据范围不一样。另外在存数据的时候,CHAR列删除了尾部的空格,而VARCHAR 则保留这些空格。
CREATE TABLE vc (v VARCHAR(4), c CHAR(4));
INSERT INTO vc VALUES ('ab ', 'ab ');
查看长度
select length(v),length(c) from vc;
枚举类型ENUM
有时候可以使用枚举类型替代字符类型。枚举可以把一些不重复的字符串存储为成一个预定义的集合。MySQL在内部会将每个值所在枚举的位置保存为整数,并且在表的.fm文件中保存“数字-字符串”映射关系的查找表。
create table enum_test(
e ENUM('JAVA','C++','C','GO','RUBY') NOT NULL DEFAULT ''
);
insert insert enum_test(e) values('JAVA'),('C++');
这三列实际存储的是整数,而不是字符串。可以通过在数字上下文环境检索看到这个双重属性。
select e + 0 from enum_test;
所以在使用的时候,如果使用数字作为枚举值那么就会造成混乱。另外枚举在排序的时候使用的是内部存储的整数进行排序的,但是这个可以通过FIELD()函数指定显式的指定排序。
select * from enum_test order by FIELD(e, 'GO','C','C++','JAVA','RUBY');
缺点
枚举的内容是固定,如果你需要添加一个枚举或者删除一个枚举,则需要使用ALTER TABLE。如果修改的枚举类有使用,则会造成现有数据的混乱。所以在使用的时候确定好这个枚举值是否会经常的改变。
优化注意点
类型选择
更小的通常更好
应该尽量使用可以正确存储数据类型的最小数据类型。更小的数据类型通常占用更少的内存缓存、CPU、磁盘,在处理的时候使用CPU的周期更少。例如:若是存储的字符是固定的长度,则使用char则比varchar更好
简单就好
简单数据类型的操作使用的CPU更少。例如整型比字符操作代价更低。因为字符集和校对规则(排序规则)使字符比较比整型比较更复杂。
例子:① 使用MySQL的内建类型存储时间(date、TIMESTAMP、DATETIME等),而非字符串。② 存储IP使用整型。
尽量避免NULL
尽量指定列为NOT NULL,除非真的需要存储NULL。
当可为NULL的列作为索引的时候,每个索引记录都需要一个额外的字节。例外:InnoDB使用单独的位(bit)存储NULL值,所以对于稀疏数据具有很好的空间利用率。
选择标识列
标识列的类型选择是很重要的,标识列一般会作为关联列,或者查询其他相关的表内容,标识列不同的类型,实现的效果性能会有差异。
① 标识列的数据类型应当和关联表中对应列的数据类型一致
② 选择的时候要考虑存储类型还有存储类型在MySQL计算和比较的过程。
③ 标识列的类型尽量不要选择ENUM和SET类型。比较好的选择是使用整数类型。另外字符类型也不太建议,消耗内存,比较比整数类型慢。
④ 对于完全“随机”的字符串需要多加注意,如MD5()、SHA1()、UUID()等。这些函数产生的字符会随机分布在很大的内存中,会导致INSERT和一些SELECT很慢。
如果存储UUID值可以移除’-’;或者用HEX()函数转换UUID为16位字节的数字,并且存在在BINARY(16)列中,检索的时候使用HEX()函数格式化为十六进制格式。
MySQL schema设计注意点
太多列
MySQL在存储引擎API工作的时候需要在服务层和存储引擎层之间通过行缓冲格式拷贝数据,然后在服务器层将缓冲内容转换成各个行。
太多的关联
全能的枚举
注意防止过度的使用枚举,枚举的类型太多会使结构凌乱,同时如果枚举的值经常变化会给数据库带来压力。
其他(IP和UUID的处理案例)
-- 创建表
CREATE TABLE `test` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'PK',
`ip` int(12) unsigned NOT NULL,
`uuid` binary(16) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 添加数据,其中INET_ATON将IP解析为整型类型,UNHEX解析为二进制
INSERT INTO `test` ( `ip`, `uuid`)
VALUES
(INET_ATON('255.255.255.255'), UNHEX(REPLACE(UUID(),'-','')));
-- 查询的时候,将IP和UUID都要反解析
select HEX(uuid),INET_NTOA(ip) from test where id = 1;
提高ALTER TABLE 速度
MySQL的ALTER TABLE 操作对大表的性能来说是个大问题。MySQL大部分修改表结构都是新建一个新的结构的空表,从旧表中查询出所有的数据插入新表,然后删除旧表。这个操作很长时间,如果内存不足但是表有特别的大,还有很多的索引,那么这个时间就更长了。
并不是所有的ALTER TABLE操作引起新建表。比如设置列的默认值,有两种方法
-- 修改默认值,这个方法是很快的,直接修改的是.fm文件,没有表的重建操作
alter table fcm_purchase_ticket alter column `certificate_import_status` set default 0;
-- 这种方法,会引起表的操作,耗时更长
alter table fcm_purchase_ticket modify column `certificate_import_status` NOT NULL default 0;