Mysql数据库优化 列的选择---转载
对一个设计拙劣或者没有做index的schma进行优化,可以很大程度的改善性能。
如果想获得很好的性能,就需要对你运行的特定的queries来设计schema和索引,
你需要估计不同类query的性能需求,和使用的频度,以及需要检索的字段和检索
的条件。优化是一个权衡,索引可以提高检索速度,但是会降低更新速度,一个反
范式的schema可能会在某些查询下加快速度,但在其他情况下可能降低速度。添加
冗余字段、计数器、summary表可以优化查询,但是维护起来很困难。
选择最优的数据类型:
Mysql支持大量的各种个样的数据类型,如何正确的选择类型来存储数据是产生高性能
的关键。
1.足够大的越小的类型越好
小的类型通常更高效,因为他们使用了更少的磁盘空间、内存和cpu高速缓存,需要更少
的CPU时钟周期。但是也不要低估的存储值的范围,增大schema多个地方的数据类型也是
一件痛苦和耗时的操作。
2.简单就好:
简单的类型需要更少的时钟周期,整数的比较要比字符串的比较要快。,比如你应该存储
mysql内置的类型而不是字符串来存贮日期和时间,使用整数来存储ip。
3.尽可能避免null字段:
尽可能的在定义的字段上添加NOT NULL,MySQL对于可以为null的列很难优化,
因为它让索引、索引统计以及值的比较变得复杂,nullable的列会使用更多的存储空间,并且需要一些特殊处理,对nullable的列建索引,每个entry需要额外的数据,在MyISAM甚至会使定长索引变成变长的。对于没有值的列,你可以使用一些特殊的值来代表,比如0,空字符串。将null变成not null可能对性能的提高不是很大,但是如果你打算对一个列见索引,那么要避免它是nullable的。
选择一个列的数据类型,首先决定大体上是什么类型的:整数、字符串等等。然后在再这些类型中选择合适的MySQL提供的类型。比如DATETIME和TIMESTAMPE可以存储相同的数据:日期和时间,精度为1秒。但是Timestamp使用了一半的空间,并且是时区敏感和一些特殊的自动更新的功能。但是具有很小的值的范围,到2038年就over了。
MYSQL为了兼容性提供了很多的别名,比如INTEGER,BOOL,NUMERIC,他们只是别名,不影响性能。
数字类型:
数字类型包括整数和浮点数类型,整数类型tinyint,smallint,mediumint,int,
bigint,他们分别占8,16,24,32,64个字节。整数类型可以使用unsigned属性,
tinyint unsigned可以存储0~255。MySQL的整数计算通常使用的是64位的bigint。
MySQL可以指定整数类型的宽度,但是这个宽度并不是限制数据的范围,只是用于指定交互式的工具显示保留的字符个数,在存储上INT(1)和INT(20)是等价的。
浮点类型:
浮点书类型有小数部分,但是他们并不是仅仅针对浮点数的,你可以使用DECIMAL来表示BIGINT存储不下的整数,MySQL支持两类:精确和非精确类型。
FLOAT和DOUBLE支持近似的标准的浮点计算,如果你需要知道计算的精确结果,你需要平台下浮点数的实现。DECIMAL可以存储精确的分数,MySQL5.0以上支持精确的数学计算,但是浮点类型的数学计算效率会更高,存储空间更小。浮点类型和DECIMAL都可以指定精度,比如DECIMAL(18,9).由于空间和计算的效率问题,只有需要精确的结果时,我们才使用DECIMAL。
字符串类型:
MySQL支持很多的字符串类型,从版本4.1开始,支持每个列使用一种字符集,如果这么做,会很大的影响性能。
VARCHAR和CHAR类型:
有两种主要的字符串类型VARCHAR和CHAR:
VARCHAR主要存储变长的字符类型,会比固定长度的类型要节省空间,因为它只需要和实际需要用的空间一样大,VARCHAR指定的长度并不是申请那么大的空间,只是最大可能占用的空间。使用1,2个额外的字节来存储长度,比如VARCHAR(10)最大会占11个字节,VARCHAR(1000)最大会占用1002个字节。
由于VARCHAR能够节省空间,所以有助于提高性能,但是由于行是变长的,如果行大到无法在原来的位置存储,那么在MyISAM会产生行碎片,InnoDB会分页。
MySQL 5.0以上不会自动删除掉结尾的空白。
通常在最长的数据要比平均的长度大很多,不会频繁更新这个字段的情况下使用VARCHAR。
CHAR是固定长度的类型,它会申请指定长度的空间。存储的时候默认会删除结尾的空白,
如果存储短的,并且长度差不多的字符串,使用CHAR是非常好的,比如存储MD5的用户密码。
对于频繁跟新的字段,使用CHAR也是比较好的选择,可以使用CHAR(1)来代表Y和N的值,这比VARCHAR(1)少用一个字节。
BINARY和VARBINARY类型用于存储二进制的字符串,和传统的字符串类似,只是存储的是字节而不是字母。BINARY字符串的比较要比普通字符串要快。
BLOB和TEXT类型:
BLOB和TEXT是用来存储大规模的数据的,分别用于二进制和字符串类型。还有其他同族的类型:TINYTEXT,SMALLTEXT,TEXT,MEDIUMTEXT,LONGTEXT,和二进制类型TINYBLOB,SMALLBLOB,BLOB,MEDIUMBLOB,LONGBLOB.
BLOB和TEXT的区别是一个用来存储二进制的,一个用来存储文本的他有字符集和编码。
BLOB和TEXT类型和其他类型排序不同,他不会将全部长度的字符串排序,他只会排序前
max_sort_length字节。如果你需要排序跟少的字符你可以减少max_sort_length,或者使用order by substring(column,length)。MySQL不能对这些类型的全部长度建索引,所以不能够使用索引来排序。
内存存储引擎不支持BLOB和TEXT类型,所以使用BLOB和TEXT列的查询,隐含的使用了On-disk临时表。即使你配置MySQL临时表在内存中,仍然需要很昂贵的系统调用。最佳的实践是不要使用BLOB和TEXT类型除非你真的需要,如果不可避免,那么可以使substring(column,length)类转换成字符串类型,这样可以使用in-memory表。需要确认使用足有短的substring,临时表的大小没有超出max_head_table_size或者tmp_table_size,否则会使用on-disk MyISAM表。
EXPLAIN的Extra列包含“Using temporary"表明这个查询使用了隐式的临时表。
使用ENUM来代替字符串类型
有时候我们可以使用ENUM列来代替传统的字符串类型,ENUM列可以存储65535个不同的字符串值。MySQL存储他们非常的紧凑,压缩为1~2个字节。每个值的内部存储都是一个整数,在.frm文件保存了数字到字符串的一个映射。
引用
mysql> CREATE TABLE enum_test(
->
e ENUM('fish', 'apple', 'dog') NOT NULL
-> );
mysql> INSERT INTO enum_test(e) VALUES('fish'), ('dog'), ('apple');
mysql> SELECT e + 0 FROM enum_test;
+-------+
| e + 0 |
+-------+
|
1 |
|
3 |
|
2 |
+-------+
ENUM字段排序是按照内部存储的整数排的,你可以显示的使用FIELD来指定排序的方式。
引用
mysql> SELECT e FROM enum_test ORDER BY FIELD(e, 'apple', 'dog', 'fish');
+-------+
| e
|
+-------+
| apple |
| dog
|
| fish |
+-------+
ENU