mysql数据类型优化

选型原则:

1、在保证足够用的前提下尽量选择最小类型!  越小消耗的cpu越少

 2、简单就好,使用简单数据类型的操作通常需要更少的cpu周期;比如字符集和校对规则(排序规则)使字符比较比整型比较更加复杂,应该使用mysql内建的类型(data,time,datatime)来存储日期时间而不是字符串,应该用整型存储ip地址  因为字符的校对、排序规则要复杂    整形比字符代价更低

3、尽量避免使用null尤其是MyISAM引擎,尽管将null改为not  null 带来的性能提升比较小,但是如果你打算在列上建立索引则强烈建议改为not null    ,对含有null的字段添加索引会使索引的计算更加复杂,且还需要额外多一个字节

 

 

整形:

TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT。分别8,16,24,32,64为存储空间,范围-2(N-1)-2(N-1)-1,其中N是存储空间的位数

如tinyint 的范围是 -2(8-1)~2(8-1)即 -128~127 如果加上UNSINGED(非负)存储的正整数海多出一倍(0~255)

 

实体类型:

FLOAT 和 DOUBLE 类型支持使用标准的浮点运算进行近似计算

在需要对小数进行精确计算时,才使用DECIMAL来表示(mysql5.0以上) 相对而言,CPU直接支持原生浮点计算,所以浮点计算明显更快

 浮点型以及 DECIMAL 在存取时,都需要额外的空间和计算的开销,
     所以应该尽量只对小数进行精确计算时才使用 DECIAML;
     如果数据量比较大的时候,可以考虑使用 BIGINT 代替 DECIAML。 
     // 这就是为什么微信的数据库(猜的因为接口都是分为单位)使用 BIGINT 来做处理,
         目的就是为了节省 MySQL 计算带来的额外损耗;
 
 
BLOB 和 TEXT 类型
 
     MySQL 把每个 BLOB 和 TEXT 值当作一个独立的对象处理。
     两者都是为了存储很大数据而设计的字符串类型,分别采用二进制和字符方式存储。

日期和时间类型:

datetime
    能保存大范围的值,从1001-9999年,精度为秒,格式YYYYMMDDHHMMSS的整数中,和时区无关
timestamp
    保存了从1970年1月1日午夜的秒数,到2038年,显示的值和时区有关系。

 

 

整型数据优化

①存储人的年龄应该使用哪种数据类型?答:使用tinyint类型(无符号型)

②存储乌龟的年龄应该使用哪种数据类型?答:使用smallinit类型(无符号型)

③存储一个1500万数据的数据表其主键id应该选择哪种数据类型?答:使用mediumint(无符号型),大约在0-1600万左右

①考虑空间问题

②考虑范围问题(unsigned无符号)

字符串类型优化

char(length)占用的空间为 固定的,与内容多少无关;

varchar(length)占用的空间为 实际内容字符个数*字节 + 1

 

①如果要存储一个11位的手机号码?答:选择char(11)比较合适

②如果要存储一个32位的md5加密密码?答:选择char(32)比较合适

③如果要存储一个用户名或一个标题,由于不确定具体要存放多少个字符,为了避免空间的浪费建议使用varchar类型。

④如果要存储一个描述信息(不超过250个汉字),使用varchar(255)比较合适。

如果要存储一个文本信息(文章内容),其超过了255个字符,建议使用text文本类型。

 

时间类型优化

在实际应用中,由于date类型主要用于存储时间信息,但是在php中,我们有相关的函数可以对整型数据和时间进行转化,所以实际应用中,大部分情况存储时间都是转化为整型数据直接存储的

 

5、枚举类型与集合类型

 

如果程序中有单选或多选情况,不建议使用varchar类型,而建议使用枚举类型或集合类型。

6、IP类型数据的存储

 

经常要保存IP地址,这个时候不建议使用varchar类型来保存数据,而建议使用整型来保存IP信息

 

//PHP中ip转整形

echo ip2long("192.168.1.1");

$ip_long = sprintf('%u',ip2long("192.168.1.1"));//解决为负数的情况

//整形转ip

echo long2ip(3232235777);

 

 

1、大多数的MySQL服务器都开启了查询缓存提高查询速度 如果使用mysql自带的函数则不会开启查询缓存

2. EXPLAIN 你的 SELECT 查询 EXPLAIN 的查询结果还会告诉你你的索引主键被如何利用的,你的数据表是如何被搜索和排序的……等等

3. 当只要一行数据时使用 LIMIT 1 

4. 为搜索字段建索引 

索引并不一定就是给主键或是唯一的字段。如果在你的表中,有某个字段你总要会经常用来做搜索,那么,请为其建立索引吧

例如,当你需要在一篇大的文章中搜索一个词时,如: “WHERE post_content LIKE ‘%apple%'”,索引可能是没有意义的

5.如果你的应用程序有很多 JOIN 查询,你应该确认两个表中Join的字段是被建过索引的。这样,MySQL内部会启动为你优化Join的SQL语句的机制

6.如果你想随机取一条数据时千万不要 ORDER BY RAND()   你可以全查出来在用php的随机函数取值

7. 避免 SELECT * 

8. 永远为每张表设置一个主键ID 除了某些关联表外键

9. 使用 ENUM 而不是 VARCHAR  如果你有一个字段,比如“性别”,“国家”,“民族”,“状态”或“部门”,你知道这些字段的取值是有限而且固定的,那么,你应该使用 ENUM 而不是 VARCHAR。

10. 从 PROCEDURE ANALYSE() 取得建议 (数据打的时候才有用和准确)

11. 尽可能的使用 NOT NULL  除非你有一个很特别的原因去使用 NULL 值,你应该总是让你的字段保持 NOT NULL

12. Prepared Statements 

13. 无缓冲的查询 

14. 把IP地址存成 UNSIGNED INT 

15. 固定长度的表会更快 

很多程序员都会创建一个 VARCHAR(15) 字段来存放字符串形式的IP而不是整形的IP。如果你用整形来存放,只需要4个字节,并且你可以有定长的字段。而且,这会为你带来查询上的优势,尤其是当你需要使用这样的WHERE条件:IP between ip1 and ip2。 

我们必需要使用UNSIGNED INT,因为 IP地址会使用整个32位的无符号整形。 

而你的查询,你可以使用 INET_ATON() 来把一个字符串IP转成一个整形,并使用 INET_NTOA() 把一个整形转成一个字符串IP。在PHP中,也有这样的函数 ip2long() 和 long2ip()。 
1 $r = "UPDATE users SET ip = INET_ATON('{$_SERVER['REMOTE_ADDR']}') WHERE user_id = $user_id"; 

16. 垂直分割 

“垂直分割”是一种把数据库中的表按列变成几张表的方法,这样可以降低表的复杂度和字段的数目,从而达到优化的目的。(以前,在银行做过项目,见过一张表有100多个字段,很恐怖) 

示例一:在Users表中有一个字段是家庭地址,这个字段是可选字段,相比起,而且你在数据库操作的时候除了个人信息外,你并不需要经常读取或是改写这个字段。那么,为什么不把他放到另外一张表中呢? 这样会让你的表有更好的性能,大家想想是不是,大量的时候,我对于用户表来说,只有用户ID,用户名,口令,用户角色等会被经常使用。小一点的表总是会有好的性能。 

示例二: 你有一个叫 “last_login” 的字段,它会在每次用户登录时被更新。但是,每次更新时会导致该表的查询缓存被清空。所以,你可以把这个字段放到另一个表中,这样就不会影响你对用户 ID,用户名,用户角色的不停地读取了,因为查询缓存会帮你增加很多性能。 

另外,你需要注意的是,这些被分出去的字段所形成的表,你不会经常性地去Join他们,不然的话,这样的性能会比不分割时还要差,而且,会是极数级的下降。 

17. 拆分大的 DELETE 或 INSERT 语句 

如果你需要在一个在线的网站上去执行一个大的 DELETE 或 INSERT 查询,你需要非常小心,要避免你的操作让你的整个网站停止相应。因为这两个操作是会锁表的,表一锁住了,别的操作都进不来了。 

Apache 会有很多的子进程或线程。所以,其工作起来相当有效率,而我们的服务器也不希望有太多的子进程,线程和数据库链接,这是极大的占服务器资源的事情,尤其是内存。 

如果你把你的表锁上一段时间,比如30秒钟,那么对于一个有很高访问量的站点来说,这30秒所积累的访问进程/线程,数据库链接,打开的文件数,可能不仅仅会让你泊WEB服务Crash,还可能会让你的整台服务器马上掛了。 

所以,如果你有一个大的处理,你定你一定把其拆分,使用 LIMIT 条件是一个好的方法。下面是一个示例:


while (1) { 
//每次只做1000条 
mysql_query("DELETE FROM logs WHERE log_date <= '2009-11-01' LIMIT 1000"); 
if (mysql_affected_rows() == 0) { 
// 没得可删了,退出! 
break; 

// 每次都要休息一会儿 
usleep(50000); 
}

18. 越小的列会越快 

对于大多数的数据库引擎来说,硬盘操作可能

19. 选择正确的存储引擎 

在 MySQL 中有两个存储引擎 MyISAM 和 InnoDB,每个引擎都有利有弊。酷壳以前文章《MySQL: InnoDB 还是 MyISAM?》讨论和这个事情。 

MyISAM 适合于一些需要大量查询的应用,但其对于有大量写操作并不是很好。甚至你只是需要update一个字段,整个表都会被锁起来,而别的进程,就算是读进程都无法操作直到读操作完成。另外,MyISAM 对于 SELECT COUNT(*) 这类的计算是超快无比的。 

InnoDB 的趋势会是一个非常复杂的存储引擎,对于一些小的应用,它会比 MyISAM 还慢。他是它支持“行锁” ,于是在写操作比较多的时候,会更优秀。并且,他还支持更多的高级应用,比如:事务。 

20. 使用一个对象关系映射器(Object Relational Mapper) 

使用 ORM (Object Relational Mapper),你能够获得可靠的性能增涨。一个ORM可以做的所有事情,也能被手动的编写出来。但是,这需要一个高级专家。 

ORM 的最重要的是“Lazy Loading”,也就是说,只有在需要的去取值的时候才会去真正的去做。但你也需要小心这种机制的副作用,因为这很有可能会因为要去创建很多很多小的查询反而会降低性能。 

ORM 还可以把你的SQL语句打包成一个事务,这会比单独执行他们快得多得多。 

目前,个人最喜欢的PHP的ORM是:Doctrine。 

21. 小心“永久链接” 

“永久链接”的目的是用来减少重新创建MySQL链接的次数。当一个链接被创建了,它会永远处在连接的状态,就算是数据库操作已经结束了。而且,自从我们的Apache开始重用它的子进程后——也就是说,下一次的HTTP请求会重用Apache的子进程,并重用相同的 MySQL 链接。 

* PHP手册:mysql_pconnect() 

在理论上来说,这听起来非常的不错。但是从个人经验(也是大多数人的)上来说,这个功能制造出来的麻烦事更多。因为,你只有有限的链接数,内存问题,文件句柄数,等等。 

而且,Apache 运行在极端并行的环境中,会创建很多很多的了进程。这就是为什么这种“永久链接”的机制工作地不好的原因。在你决定要使用“永久链接”之前,你需要好好地考虑一下你的整个系统的架构。

posted @ 2017-07-11 17:09  虚无缥缈的云  阅读(251)  评论(0编辑  收藏  举报