@lgh-dev
2018-04-10T10:57:32.000000Z
字数 5771
阅读 799
MySQL
更小的数据类型通常更快,因为她们占用更少的磁盘,内存和CPU缓存,处理需要的cpu周期也更少
简单的数据类型操作通常需要更少的cpu周期
- 可为NULL是列的默认属性,查询中包含可为null的列,对Mysql来说难优化,也使得索引,索引统计和值比较都更复杂,可为NULL的列会使用更多的存储空间,当可为NULL的列被索引时,每个索引需要一个额外的字节。
- 如果计划在列上创建索引,应尽量避免设计为可为NULL的列。
- DATETIME和TIMESTAMP列都可以存储相同类型的数据:时间和日期,精确到秒,然而TIMESTAMP只使用DATETIME一半的存储空间,而且会根据时区变化,具有特殊的自动更新的能力。但另一方面TIMESTAMP允许的时间范围要小的多。
- TINYINT, SMALLINT,MEDIUMINT, INT, BIGINT,分别使用8、16、24、32、64位存储空间,存储的值的范围是 -2(n-1) 到 2(n-1) -1,n是存储空间的位数。
- 整数类型有可选的UNSINGED属性,表示允许负值,大致使正数的上线提高一倍。
- Mysql可以为整数类型指定宽度,对大多数应用是没有意义的,他不会限制值的合法范围,只是规定mysql交互工具显示字符的个数。
- 有符号和无符号类型使用相同的存储空间。
- 实数是带有小数部分的数字,支持精确类型和不精确类型
- float和double支持标准的浮点运算进行近似运算,decimal支持精确计算,但cpu不支持decimal计算,是由mysql自身实现的,cpu支持原生浮点运算,所以浮点运算明显更快。
- decimal只是一种存储格式,在计算中decimal会转换为double类型。
- 浮点类型存储同样范围的值时,通常比decimal使用更少的空间。float使用4个字节,double使用8个字节,mysql使用double作为内部浮点计算类型.
- varchar类型用于存储可变长字符串,比定长更省空间,因为它仅使用必要的空间。当mysql表使用ROW_FORMAT=FIXED创建,每一行都是定长。
- varchar需要1或2个额外的字节记录字符串的长度,列的最大长度<=255个字节,使用1个字节,否则使用2个。 Example: varchar(100) 需要101个字节存储, varchar(300)需要302个字节存储空间。
- varchar节省了存储空间,对性能有帮助,但由于行是变长的,在update时可能使行变得比原来长,这就导致要做额外的工作。
- varchar合适:字符串列最大长度比平均长度大很多; 列的更新很少,避免碎片化;使用了复杂的字符集,每个字符都使用不同的字节数存储;
- char类型是定长的: char的值会根据需要采用空格进行补充方便比较.
- 当存储char的值时,mysql
- char 适合存储很短的字符串,或者所有值都接近同一个长度。 比如密码MD5的值
- 对于经常变更的数据char比varchar更好,因为char类型不易产生碎片。
- 对于非常短的列,char比varchar在存储空间上更有效率; 比如: char(1)来存储只需要一个字节,但是varchar(1)却需要两个字节,还有一个记录长度的额外字节。
- 二进制字符串存储的是字节码而不是字符
- Mysql比较Binary字符串,每次按照一个字节,并且根据该字节的数值进行比较,因此二进制比较比字符比较简单而且快。
- BLOB和TEXT都是为了存储很大的数据设计的字符串类型,分别用二进制和字符存储。
- MySQL把每个BLOB和TEXT值当作一个独立的对象处理.当值太大时,InnoDB会使用专门的外部存储区域存储,此时每个值在行内需要1~4个字节存储一个指针,然后在外部存储实际的值。
- BLOB和TEXT的区别是BLOB存储的是二进制数据,没有排序规则和字符集,而TEXT类型有。
- MySQL不能把BLOB和TEXT全部长度的字符串进行索引,也不能使用这些索引消除排序。
- 枚举列可以把一些不重复的字符串存储成一个预定义的集合。
- MySQL在存储枚举时非常紧凑,会根据列表值的数量压缩到一个或者两个字节中。
- MySQL在内部会把每个值在列表中的位置保存为整数,并且在表的.frm文件中保存“数字-字符串"的映射关系。
- 枚举字段是按照内部存储的整数而非定义字符串进行排序的,一种绕过限制的方式是按照需要的顺序定义枚举列,在查询中使用FIELD()函数显式指定排序顺序,但这会导致MySQL无法使用索引消除排序.
- 枚举最不好的地方是字符串列表是固定的,添加或删除字符串必须使用ALTER TABLE。
- 特定情况下,把CHAR/VARCHAR列与枚举列进行关联会比直接关联CHAR/VARCHAR列更慢。
- 转换列为枚举类型,根据show table status命令输出结果中Data_length列的值,把这两列转换为枚举可以表的大小缩小.
- 这个类型能保存大范围的值,从1001到9999年,精度为秒.他把日期和时间封装到
YYYYMMDDHHMMSS
的整数中,与时区无关.- 使用8个字节的存储空间.
- 默认情况下,MySQL以一种可排序的,无歧义的格式显示DATETIME的值.
- TIMESTAMP保存从1970年1月1日以来的秒数,它和UNIX时间戳相同.
- TIMESTAMP使用4个字节的存储空间.
- 范围比较少,表示1970~2038年的时间.
FROM_UNIXTIME()
把UNIX时间戳转换为日期,UNIX_TIMESTAMP()
日期转为UNIX时间戳.- TIMESTAMP显示的值依赖于时区.如果在多个时区存储访问数据TIMESTAMP和DATETIME的行为很不一样,前者提供的值与时区有关,后者保留文本表示的日期和时间。
- 可以配置任何TIMESTAMP列的插入和更新行为,TIMESTAMP列默认为NOT NULL.
- 一般尽量使用TIMESTAMP,因为它比DATETIME空间效率更高.
- 用整数存储Unix时间戳不会带来任何收益,而且不方便处理,一般不建议这么做。
- MySQL把BIT当作字符串类型,而不是数字类型.
- 当检索BIT(1)的值时,结果是包含二进制的0或1的字符串,而不是ASCII码的0或1,然而在数字上下文的场景中检索,结果将是位字符串转换为数字。
- 如果想再一个bit的存储空间中存储一个ture/false的值,另一个方法创建一个可以为空的char(0)的列,可以保存空值(NULL)或者长度为0的字符串(空字符串);
- 如果需要保存很多true/false的值,可以考虑合并这些列到一个set数据类型,它在MySQL内部以一系列打包的位集合来表示,可以有效的利用存储空间,而且MySQL有像
FIND_IN_SET()
和FILED()
这样的函数,方便在查询中使用.- 缺点是改变列价值比较高,需要alter table,一般来说,无法在set列上通过索引查找。
- 整数位上进行按位操作,使用一个整数包装一系列的位。
- 为标识列选择数据类型时,应该选择跟关联表中的对应列一样的类型.
- MySQL在内部使用整数存储ENUM和SET类型,在做比较操作时转换为字符串.
- 一旦选定一种类型,要确保所有关联表中都使用同样的类型,,混用不同的数据类型可能会导致性能问题。
- 在可以满足值的范围需求,并且预留未来增长空间的前提下,应该选择最小的数据类型。
- 整数通常是标识列最好的选择,因为他们很快而且可以使用
AUTO_INCREMENT
.- 对于标识列来说,应尽量避免使用ENUN和SET类型,它们适合存储固定信息.
- 如果可能,应该尽量避免使用字符串类型作为标识列,因为他们很耗空间,并且通常比数字类型慢。
- 尤其是MyISAM表中使用字符串作为标识列,MyISAM默认对字符串使用压缩索引,会导致查询慢很多。
- 如果使用InnoDB存储引擎,不能在数据类型不完全匹配的情况下创建外键,否则报错。
- 由MD5(),SHA1()等产生的随机字符串会任意分布在很大的空间内,会导致insert和一些select语句变得很慢.
- 因为插入值会随机写到索引不同位置,所以使得insert语句很慢,而且会导致页分裂,磁盘随机访问,对于聚簇存储引擎产生索引碎片。
- select语句变得更慢是因为逻辑上相邻的行分布在磁盘和内存的不同地方。
- 随机值会导致缓存对所有类型的查询语句效果都很差,因为会使得缓存赖以工作的访问局部性原理失效。
- IPv4地址实际上是32为无符号的整数,不是字符串,用小数点将地址分成四段的表示方法只是为了阅读方便,所以应该用无符号地址存储IP地址,这样可以节省空间, MySQL提供
INET_ATON()
和INET_NTOA()
函数进行转换。
- MySQL的存储引擎API工作时需要在服务器层和存储引擎层通过行缓冲格式拷贝数据,然后在服务器层将缓冲内容解码成各个列.
- 从行缓冲中将编码过的列转换成行数据结构的操作代价是非常高的。MyISAM的定长行结构与服务器层行结构正好匹配,无需转换; 然而,MyISAM变长行结构和InnoDB的行结构则总需要转换,转换代价依赖于列的数量。
- MySQL限制每个关联操作最多只能有61张表,一个粗略的经验法则,如果希望查询执行的快速且并发性好,单个查询最好在12个表以内做关联。
- 可以配置MySQL的SQL_MODE来禁止不可能的日期,对于新应用这是个非常好的时间经验,它不会让创建的数据库里充满不可能的值。
- 有时提升性能最好的方法是在同一张表中保存衍生的冗余数据。
缓存表
表示存储那些可以比较简单的从schema其他表获取数据的表(比如逻辑上的冗余数据)汇总表
保存的是使用group by语句聚合数据的表[数据不是逻辑冗余的]- 缓存表对优化搜索和检索查询语句很有效,这些查询语句经常需要特殊的表和索引结构;
- 缓存表可以使用不同的存储引擎,比如主表是InnoDB,用MyISAM作为缓存表的引擎将会得到更小的索引占用空间,并且可以全文索引。
MySQL并不原生支持物化视图,使用开源工具Flexviews实现物化视图.由如下部分组成
- 变更数据抓取功能,读取服务器的二进制日志并解析相关行的变更
- 一系列帮助创建和管理视图的定义的存储过程
- 一些可以应用变更到数据库中的物化视图的工具
sum
获取统计结果
mysql> alter table load_data disable keys;
--load data
mysql> alter table load_data enable keys;
良好的schema设计是普遍适用的,MySQL有他自己的实现细节要注意,尽可能保持任何东西小而简单总是好的。