当前位置: 首页 > 科技观察

MySQL使用规范手册,程序员必知

时间:2023-03-13 22:26:55 科技观察

背景随着时间的推移,平台或系统上的用户数量增加,数据库操作往往会变慢;和数据库在Java应用程序开发中尤为重要。在大多数情况下,数据库的性能决定了程序的性能。如果前期埋的坑多了,后期数据库就会成为整个系统的瓶颈;因此,在开发中更规范地使用MySQL是必不可少的。1.MySQL数据库命名规范数据库中所有表前缀均使用项目名称的首字母缩写;数据库中的所有对象名称均使用小写字母,单词之间用下划线分隔;数据库中所有对象名禁止使用MySQL保留字和关键字,涉及关键字的SQL查询需要将关键字用单引号括起来;数据库中所有对象的名称不超过32个字符,命名遵循知名原则;数据库临时表必须以pro_tmp_为前缀,以日期20190917为后缀,备份表必须以pro_bac为前缀,以时间戳为后缀;(pro是项目名的首字母缩写)数据库中存储相同数据的所有列名和列类型必须一致。二、MySQL数据库基本设计规范1、如无特殊说明,建表时将使用Innodb存储引擎。选择合适的引擎可以提高数据库的性能,比如InnoDB和MyISAM。InnoDB和MyISAM是很多人在使用MySQL时最常用的两种表类型。这两种表类型各有优缺点,视具体应用而定;basic的区别是:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持;MyISAM类型表强调性能,执行速度比InnoDB类型快,但不提供事务支持,而InnoDB提供事务支持和外键等高级数据库功能;因此,它对事务处理的支持,对外键的支持,对崩溃恢复能力和并发控制的支持,是我们在建表时首选的存储引擎。2、数据库和表的字符集统一使用UTF8。数据库和表的字符集统一使用utf8。如果有字段需要存储emoji表情,将表或字段设置为utf8mb4;因为utf8被称为万能码,不需要转码,没有乱码风险,节省空间,而且utf8mb4向下兼容utf8。3、设计数据库时,所有的表和字段都必须进行注释。使用Comment子句为表和列添加注释,或者直接在数据库连接工具的注释列中添加注意数据字典的维护是从项目开始就进行的。使用Comment子句添加注释如:--1.创建表:CREATETABLEt1(idvarchar2(32)primarykey,nameVARCHAR2(8)NOTNULL,agenumber);--2.添加表注释:Commentontablet1is'personalinformation';--3.添加字段注释:commentoncolumnt1.idis'id';commentoncolumnt1.nameis'name';commentoncolumnt1.ageis'age';使用数据库连接工具添加注释:4、单表数据量控制在500万以内,尽量将单表数据量控制在500万以内,建议数据库大小控制在500万以内;500万不是MySQL数据库的限制,但数据过多不利于修改表结构、备份和恢复数据,适当采用分库分表等方式控制单表数据量的大小。5、使用MySQL分区表需谨慎。分区就是把一个表的数据按照一定的方式分成多个更小更便于管理的部分,比如按照时间的月份,但逻辑上还是一张表;partitiontable物理上表现为多个文件,但逻辑上仍表现为同一张表,需要慎重选择partitionkey;跨分区查询效率可能较低,建议使用物理分区表来管理大数据。6、尽量满足冷热数据分离,减少表的宽度。MySQL限制每张表最多存储4096列,每行数据大小不超过65535字节。为了减少磁盘IO线程的开销,需要对表进行适当的控制。宽度,因为表越宽,加载表到内存缓冲池时占用的内存越大,会消耗更多的IO线程;另外,为了保证热数据的内存缓存命中率,更有效的使用缓存避免读取无用的冷数据,尽量将经常使用的列放在同一个表中,避免不必要的关联操作。7.保留字段的设置需谨慎。有些朋友在设计数据库表的时候,不仅设计了当前需要的字段,还预留了几个字段备用。比如我设计了一个人事表(Person),里面添加了各种必填字段,包括姓名(Name)、性别(Sex)、出生日期(birthday)等;为了以防万一,比如以后Person表可能会涉及到毕业学校、工作单位、是否结婚、照片等信息,所以增加了5个varchar2类型的字段,分别叫做Text1、Text2...Text5;这种手动操作似乎是预防性的。其实也不一定,因为大量的保留字段会浪费空间,保留字段不能众所周知,保留字段不能确认存储的数据类型,修改字段类型也可能会导致诸如锁定表。对于这种情况,可以参考以下两种解决方案:如果数量较少,且信息性质与原表密切相关,则可以直接在原表中添加字段,更新相关数据;如果数字很大,或者不是原表对象的关键属性,那么可以添加一个新表,通过键值连接起来;8、禁止在数据库中存放图片、文件等大型二进制数据。如果你在数据库表中存储文件,并且文件通常非常大。读取数据库时,会进行大量的随机IO操作。大文件使得IO操作耗时耗性能,导致数据量在短时间内急剧增加;因此,图片和文件通常存储在文件服务器中,数据库仅用于存储文件地址信息。三、MySQL数据库字段设计规范1、优先选择满足存储要求的最小数据类型。主要考虑的是索引的性能,因为列的字段越大,建立索引需要的空间就越大,所以一个页能存放的索引节点数会越少,而索引节点的数量遍历时需要的IO会比较小。越多,索引的性能越差。2.避免使用TEXT和BLOB数据类型。避免使用TEXT和BLOB数据类型。最常见的TEXT类型可以存储64K的数据。MySQL临时内存表不支持TEXT、BLOB等大数据类型。如果查询中包含此类数据,则在进行排序等操作时,不能使用内存临时表,必须使用磁盘临时表进行操作;TEXT和BLOB类型只能使用前缀索引(当索引是很长的字符序列时,这个索引会占用很多内存,而且会很慢。这时候就会使用前缀索引;所以-所谓的前缀索引就是使用索引的前几个字母作为索引,但是为了降低索引的重复率,我们还必须判断前缀索引的重复率;),因为MySQL对索引的长度有限制字段,所以TEXT类型只能使用前缀索引,TEXT列不能有默认值;如果有必要,建议将BLOB或TEXT列分离成单独的扩展表,查询时一定不要用select*,只需要取出必要的列即可。3.避免使用ENUM枚举类型。要修改ENUM值,需要使用ALTER语句;ENUM类型的ORDERBY操作效率低下;禁止使用数值作为ENUM的枚举值。4.所有列的默认值都定义为NOTNULL。数据库中所有的NULL列都需要额外的空间来存储,所以会占用更多的空间;数据库在进行比较和计算时需要对NULL值做特殊处理。5.使用TIMESTAMP(4字节)或DATETIME(8字节)来存储时间。TIMESTAMP中存储的时间范围为:1970-01-0100:00:01~2038-01-19-03:14:07;TIMESTAMP占用4个字节,与INT类型相同,但可读性高于INT类型。如果超出了TIMESTAMP的取值范围,则以DATETIME类型存储;使用字符串类型存储时间的缺点:不能使用日期函数进行比较计算,字符串存储占用空间较大。6、金融类金额数据必须使用decimal类型精度浮点数:decimal非精度浮点数:float,doubleDecimal类型为精确浮点数,计算时精度不会丢失;占用空间由定义的宽度决定,每4个字节可存放9位,小数点也占用一个字节;另外,Decimal类型可以用来存储大于bigint的数据类型。四、MySQL索引设计规范1、每张表的索引数不超过5个。索引可以提高查询效率,但是也会降低插入和更新的效率,甚至在某些情况下会降低查询效率,所以不是越多越好,要控制它的数量。2.每个Innodb表都必须有一个主键。Innodb是一个索引组织表,其数据存储的逻辑顺序与索引的顺序相同;每个表可以有多个索引,但是表的存储顺序只能是一个,Innodb按照主键索引的顺序组织表,所以不要使用频繁更新的列,UUID,MD5,HASH,字符串列作为主键。这些列不能保证数据增长的顺序。主键推荐使用自增ID值。3.尽量避免使用外键约束。不建议使用外键约束(foreignkey),但必须在表间关联键上建立索引;外键虽然可以保证数据的引用完整性,但是外键也会影响父表和子表的写操作,从而降低性能,并且会让表更加耦合。建议在业务端实现。五、MySQL数据库SQL开发规范1、推荐使用预编译语句进行数据库操作。可以重用预编译语句。同一条SQL语句可以一次解析多次使用,减少SQL编译所需时间,提高处理效率;此外,还可以有效解决动态SQL带来的SQL注入问题。2.避免数据类型的隐式转换。隐式转换如:SELECT1+"1";数字+字符隐式转换可能会导致索引失败和一些意想不到的结果。3、充分利用表中已有的索引1)避免使用双%号查询条件,如WHEREfirst_namelike'%James%',如果没有前置前缀%,只有后置前缀%,则该列执行SQL语句时会使用双%号上的索引,不会使用列上的索引。2)一条SQL语句只能使用复合索引中的一列进行范围查询。比如体重、年龄、性别三列的联合索引。如果查询条件中有weight列的范围查询,age和sex列上的索引将不会被使用;因此,在定义联合索引时,如果某列需要用于范围查询,则将该列放在联合索引的右侧。3)用notexists代替notin,因为在sql语句中执行notin会导致索引失效。4、不要使用SELECT*,必须使用SELECT查询,因为使用SELECT*查询会消耗更多的CPU、IO和网络带宽资源,而且查询时不能使用覆盖索引。5、禁止使用没有字段列表的INSERT语句,如:INSERTintotable_namevalues('1','2','3');更改为带有字段列表的INSERT语句:INSERTintotable_name('c1','c2','c3')values('1','2','3');6.避免使用子查询,可以将子查询优化为连接操作但是,通常子查询是在in子句中,并且子查询只有在查询是简单的SQL(即不包含union、groupby、orderby,和limit子句),可以将子查询转化为join关联查询进行优化;子查询性能不好的原因:子查询的结果集不能使用索引,通常子查询的结果集会存放在一个临时表中,内存临时表和磁盘临时表都不会有索引,所以查询性能会受到一定程度的影响;因为子查询会产生大量的临时表,而且没有索引,所以会消耗过多的CPU和IO资源,导致大量的慢查询。7、避免使用JOIN关联过多的表在Mysql中,对于同一个SQL关联(join)多个表,每次join都会额外分配一个关联缓存。如果一个SQL中关联的表越多,占用的内存就越大;如果程序中大量使用多表关联操作,join_buffer_size(MySQL允许的关联缓存个数)设置不合理,容易造成服务器内存溢出,影响稳定性服务器数据库性能;另外对于关联操作,会产生临时表影响查询效率,Mysql最多允许关联61张表,建议不要超过5张;8、对同一列对象进行OR判断时,只要涉及的值不超过500个,就用in代替orin,in操作可以更有效地使用索引,或者大多数情况下很少使用索引。9、禁止使用orderbyrand()进行随机排序。10、禁止对WHERE子句中的列进行函数转换和计算,因为在WHERE子句中对列进行函数转换或计算时不能使用索引。不推荐:wheredate(end_time)='20190101'推荐:whereend_time>='20190101'andend_time<'20190102'11.当明显没有重复值时,使用UNIONALL而不是UNION。UNION会将两个结果集中的所有数据合并到临时表中,然后进行去重操作;UNIONALL将不再去重结果集;12、将复杂而长的SQL拆分成多个小SQL执行大SQL,逻辑上比较复杂,是需要大量CPU计算的SQL语句;在MySQL中,一条SQL语句只能使用一个CPU进行计算;SQL拆分后可以并行执行,提高处理效率。六、MySQL数据库行为规范1、对于100万行以上数据的批量操作(updatedeleteinsert),多次进行大批量操作可能会造成严重的主从延迟;当binlog日志为行格式时,会产生大量的日志;避免大事务操作。2、对于大表,使用pt-online-schema-change修改表结构,避免大表修改造成主从延迟,避免修改表字段时锁表;pt-online-schema-change会先新建一张与原表结构相同的新表,并在新表上修改表结构,然后将原表中的数据复制到新表中,并添加一些触发器在原始表中;然后,复制新表,将原表中添加的数据也复制到新表中。复制完该行的所有数据后,将新表命名为原表,删除原表。这是把原来的DDL操作分解成多个小batch的实现。3、禁止给程序使用的账号授予super权限。当达到最大连接数时,仍然有super权限的用户运行连接。super权限只能保留给DBA处理问题的账号。4、对于程序连接的数据库账号,遵循最小权限原则。程序使用的数据库账号只能在一个数据库下使用,程序使用的账号原则上不授予drop权限。