MySQL技术内幕(SQL编程)-数据类型
一:MySQL存储引擎
MySQL插件式存储引擎可以让存储引擎层的开发人员设计他们希望的存储层(满足事务需求、满足数据放到内存中等),常见的存储引擎如下:
InnoDB存储引擎:支持事务,面向联机事务处理的应用。特点是行锁设计、支持外键、默认读取操作不会产生锁。最为常用的引擎,5.5.8版本后的默认存储引擎。
MyISAM:表锁设计、支持全文索引、不支持事务,面向OLAP数据库应用,5.5.8版本前曾是默认存储引擎。其缓冲池只缓存索引文件,不缓存数据文件。
NDB:集群存储引擎,结构是share nothing的集群架构,可提供更高级的高可用性。数据全部放在内存中,主键查找速度极快,面向OLTP数据库应用类型。
Memory:数据全放在内存中,重启或崩溃表中数据即消失,默认使用哈希索引,而不是B+树索引。
回顾1:封锁类型
- 写锁(排他锁,X锁):T对A加了写锁,只允许T读写A,其他事务不能对A加锁,直到T释放A上的锁,其降低了整个系统的并行性;
- 读锁(共享锁,S锁):T只能读不能改A,其他事务只能对A加S锁,直到T释放)
回顾2:封锁粒度
数据库中为了实现并发控制而采用封锁技术,封锁对象的大小称为封锁粒度(Granularity)。
- 表锁:开销小,锁定整张表,写操作要获得写锁,阻塞其他用户的读写操作。
- 行锁:开销大,对指定记录加锁,其他进程可对表中其他数据进行操作,较大程度支持并发处理。
二:数据类型
1.UNSIGNED:
将数字类型无符号化。INT类型范围:-2^31~2^31-1 INT UNSIGNED范围:0~2^32-1
看似适合主键自增长的类型,但实际应用中有负面影响,例如:CREATE TABLE `t1` (`a` int(10) unsigned, `b` int(10) unsigned) ;
当插入(1,2)时,SELECT a-b FROM t1会报错:[Err] 1690 - BIGINT UNSIGNED value is out of range in…
原因:a-b的十六进制结果为0xFFFFFFFF,对于无符号整型值来说为4294967295(整型最大值);对于有符号整型数来说,符号位1即负数,取反加1,最终结果为-1。
解决方式:
SET sql_mode='NO_UNSIGNED_SUBTRACTION';
SELECT a-b FROM t1;
建议:尽量不用UNSIGNED,其可能带来某些意想不到的效果,且对INT类型存放不了的数据,INT UNSIGNED同样可能存放不下,还不如使用BIGINT。
2.ZEROFILL:
`a` int(10) unsigned DEFAULT NULL : 对于int(10)来说,其实没有ZEROFILL这个属性,括号内的数字毫无意义。
`a` int(4) unsigned zerofill,插入1时a的显示结果会是0001,宽度小于4则会自动填充0。
一旦启用zerofill属性,mysql数据库为列自动添加UNSIGNED属性。
3.SQL_MODE设置:
默认为空,该设置可以允许一些非法操作,如将NULL插入NOT NULL字段,或插入非法日期。生产环境强烈建议将该值设为严格模式(严格模式是将SQL_MODE设置为STRICT_TRANS_TABLES或STRICT_ALL_TABLES中的至少一种)。
SELECT @@session.sql_mode (查看当前会话SQL_MODE设置)
SELECT @@global.sql_mode(查看当前全局SQL_MODE设置)
设置为严格模式:SET GLOBAL sql_mode='strict_trans_tables';
4.日期和时间函数:
DATETIME(8字节):范围“1000-01-01 00:00:00”到“9999-12-31 23:59:59”
DATE(3字节):范围“1000-01-01”到“9999-12-31”
TIMESTAMP(4字节):范围“1970-01-01 00:00:00”到“2038-01-19 03:14:07”实际存储“1970-01-01 00:00:00”到当前时间的毫秒数。
YEAR(1字节): 可指定宽度,YEAR(4)范围1901-2155,YEAR(2)范围1970-2070(00-69代表2000-2069)
TIME(3字节):范围“-838:59:59”-"838:59:59"。该类型可保存一天中的时间,还可以保存时间间隔
TIMESTAMP和DATETIME的区别:
除了时间范围不一样,还有:建表时TIMESTAMP可设置默认值,DATETIME不行;更新表时TIMESTAMP类型的列可以自动更新时间为当前时间。
建表案例:
`GMT_CREATE` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`GMT_MODIFIED` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
注意:执行UPDATE操作后,若值并没有得到更新,那么GMT_MODIFIED字段不会得到更新。
时间函数:
1.SELECT NOW(),CURRENT_TIMESTAMP(),SYSDATE(),SLEEP(2),NOW(),CURRENT_TIMESTAMP(),SYSDATE();
CURRENT_TIMESTAMP和NOW相同,返回执行SQL语句的时间;SYSDATE返回执行到当前函数时的时间
2.DATE_ADD和DATE_SUB:SELECT DATE_ADD(NOW(),INTERVAL -30 DAY);可以使用的数据类型:MICROSECOND、SECOND、MINUTE、HOUR、WEEK、MONTH
3.DATE_FORMAT:SELECT DATE_FORMAT(NOW(),'%m/%d/%Y'); 07/06/2016
注意:SELECT DATE_FORMAT(NOW(),'%Y-%m-%d')='2017-01-01';存在的问题:一般来说表中都会有一个对日期类型的索引,如果使用上述的语句,优化器绝对不会使用索引,也不可能通过索引来查询数据,所以此查询的执行效率非常低。
5.数字类型和字符类型:
1.单精度的FLOAT和双精度的DOUBLE都是非精确的类型,并不能保证运算的正确性。FLOAT(M,D):M表示该值显示M位,D为小数点后面的位数,在保存值时会四舍五入。
2.DECIMAL和NUMERIC被视作相同的类型,该数据类型用于要求非常高的精确度的计算中,MySQL在内部把DECIMAL数据类型存储为字符串,更精确地保留它们的值。
3.对列的字符集设置: a VARCHAR(10) CHARSET gbk;
4.排序规则的命名:_ci结尾表示大小不敏感(case insensitive) _cs表示大小写敏感(case sensitive) _bin表示二进制的比较。utf8字符集默认的排序规则是utf_general_ci,大小写不敏感。当插入a和A时,会被视作一致的字符而返回(SELECT 'a'='A';显示为1)。【在有关场景,如用户填写注册名时,字段要注意区分大小写】。修改排序规则:ALTER TABLE t MODIFY COLUMN a VARCHAR(10) COLLATE UTF8_BIN; 排序规则还会影响索引:当使用utf_general_ci时,列t中含有A及a,则创建唯一索引会提示有重复数据。
5.CHAR(N):保存固定长度的字符串。N的范围0-255。VARCHAR(N):保存变长字符类型。N的范围0-65535。N都代表字符长度,而非字节长度。对于CHAR来说,数据库会自动对存储列的右边进行填充直到长度为N,而在读取时会自动将填充的字符串删除。LENGTH函数表示字符串占用的字节数,CHAR_LENGTH表示字符长度。
6.VARCHAR在存储时需要在前缀长度列表加上实际存储的字符,当小于255字节时需要1字节的空间,大于255字节时需要2字节的空间。所以VARCHAR(10)的最大占用空间数是11字节,其中的1个字节来存放字符长度。
7.BINARY和VARBINARY:与CHAR和VARCHAR类似,BINARY和VARBINARY存储的是二进制的字符串,而非字符型字符串,其没有字符集的概念,排序和比较按照二进制值进行。BINARY(N)和VARBINARY(N)中的N都表示字节长度。BINARY填充字符是0x00,而CHAR填充字符为0x20。
8.BLOB用来存储二进制大数据类型,大多数情况下BLOB类型视为足够大的VARBINARY类型的列,同样TEXT类型的列视为足够大的VARCHAR类型的列。BLOB和TEXT类型不能有默认值。排序时只使用列的前max_sort_length字节(默认1024,可设置SET GLOBAL max_sort_length=2048)。为了有效存储类型为BLOB或TEXT的大数据类型,一般将列的值存放到行溢出页中,数据页存储的行数据只包含BLOB或TEXT类型数据前一部分数据。
9.ENUM和SET类型都是集合类型,ENUM最多可枚举65535个元素,SET类型最多可枚举64个元素。