您现在的位置是:网站首页> 编程开发> 性能 编程开发

系统开发设计规范

2021-08-19性能 118人已围观

简介1. 服务分层2. 设计规约共通设计文档类业务逻辑层数据访问层3. 安全规约接口层业务逻辑层4. 批处理5. MySQL 数据库建表规约索引规约1. 服务分层服务分层2. 设计规约共通1强制                服务间调用,不能出现同级调用,必须自上而下调用。(请参考服务分层)2强制   &

系统开发设计规范

最后更新:2021-10-23 11:38:40

推荐指数

购买金额:1.00

立即购买
  • 1. 服务分层

  • 2. 设计规约

    • 共通

    • 设计文档类

    • 业务逻辑层

    • 数据访问层

  • 3. 安全规约

    • 接口层

    • 业务逻辑层

  • 4. 批处理

  • 5. MySQL 数据库

    • 建表规约

    • 索引规约


1. 服务分层

服务分层

%E6%9C%8D%E5%8A%A1%E5%88%86%E5%B1%82 (1).png


2. 设计规约

共通

1

强制                

服务间调用,不能出现同级调用,必须自上而下调用。(请参考服务分层)

2

强制                

系统必须支持横向扩展

  • API服务无状态 - 服务本身不保存数据,需要的数据都从独立的存储设备中读取和保存,如数据库,缓存中间件,ElasticSearch等

  • API服务有状态 - 服务保存数据在自身节点上,且该部分数据只需要提供给服务自身节点读取,不需要提供给服务的其他节点读取

3

强制                

服务接口必须符合幂等性要求。对于相同的请求,如果重复发送,其处理结果必须要保持一致。

  • 对于请求中存在能够唯一标识处理对象的字段,如订单号,商品ID等,则依据该字段判断是否重复处理

    • 反例结果:订单已取消,返回失败

    • 正例结果:   返回订单取消成功

    • 举例:取消订单接口,对于订单号XXX,因为网络等原因,请求被重复发送了多次。对于第一次取消订单请求,返回订单取消成功,第二次及以后的取消订单请求的处理应该如何处理?

  • 对于请求中不存在能够唯一标识的字段,则需要在请求中添加请求ID。客户端需保证相同的请求只发送统一请求ID, 服务端需保证对于同一请求ID,返回相同的处理结果

    • 举例: 会员添加积分接口的设计。由于添加会员积分的场景有很多,注册、推荐会员、签到等,这个接口在设计时没有字段可以唯一标识添加积分的处理对象,则需要在接口中添加积分交易ID, 这个ID由客户端创建且做唯一性管理。服务端接口则需判断交易ID,如果对于交易ID之前已处理成功,则需返回处理成功结果。

4

强制                

服务接口必须向下兼容。必须要保证新旧版本兼容。如果接口无法兼容的情况下,采取新建接口的方式。

  • 举例:版本V1.0中订单交易中,订单的渠道只有商城,且无标识渠道的字段。版本V1.1中,订单的渠道增加了访销,车销。那么V1.1中的订单接口中,需要添加订单渠道字段,且必须把该字段设定为非必须字段,默认值为"商城"。

5

强制                

程序要有闭环。程序必须能够把一件事情做完,中途发生的程序歧路需要考虑到,比如一个订单有十个状态,出现异常时不能让订单夯在某个状态,有开始有结束,就像补偿超次后的闭环是发预警闭环到人。            
6

强制                

重要服务提供降级托底方案,例如返回给首页数据的接口,当运营未设置时,后台程序需要按照一定规则补充数据。            
7

强制                

接口超时时间控制:防止接口超时导致整体服务夯住            
8

强制                

方法入参检查:不能信任调用方遵守规则,要自己做好防备,接口文档中定义了某些字段和规则,调用方不按文档调用会造成程序处理异常。            
9

推荐                

接口重试机制:根据业务控制,不是所有接口都可以重试,主要是业务防重控制            
10

推荐                

异常数据的处理:数据和环境总会有异常的情况,考虑程序的抗异常能力,程序的异常要能自己捕获和处理,不能抛给调用方-----数据库的数据会有异常状况,比如两个关联订单,理论上不会出现一个有一个没有,如果数据有问题通过一个查询到另外一个不判断null直接使用会空指针,自己程序的异常应该自己捕获,自己处理,做到万无一失。            
11

推荐                

需求分析与系统设计在考虑主干功能的同时,需要充分评估异常流程与业务边界。

  • 反例: 用户在淘宝付款过程中,银行扣款成功,发送给用户扣款成功短信,但是支付宝入款时 由于断网演练产生异常,淘宝订单页面依然显示未付款,导致用户投诉。

12

推荐                

系统设计阶段,共性业务或公共行为抽取出来公共模块、公共配置、公共类、公共方法等,避免出现重复代码或重复配置的情况。

  • 说明: 随着代码的重复次数不断增加,维护成本指数级上升。

13

推荐                

在保证缓存和DB一致性的基础上,提升时效性            
14

推荐                

关键节点(如外部接口调用)的入出参打印,解决日志定位困难可添加夸服务的全局流水号或者业务id串联线索            
15

推荐                

重要接口单独提供服务,减少别的接口因为资源占用对重要接口的影响            
16

参考                

系统设计主要目的是明确需求、理顺逻辑、后期维护,次要目的用于指导编码。

  • 说明: 避免为了设计而设计,系统设计文档有助于后期的系统维护,所以设计结果需要进行分类归档保存。

17

参考                

设计的本质就是识别和表达系统难点,找到系统的变化点,并隔离变化点。

  • 说明: 世间众多设计模式目的是相同的,即隔离系统变化点。

18

参考                

系统架构设计的目的:

  • 确定系统边界。确定系统在技术层面上的做与不做。

  • 确定系统内模块之间的关系。确定模块之间的依赖关系及模块的宏观输入与输出。

  • 确定指导后续设计与演化的原则。使后续的子系统或模块设计在规定的框架内继续演化。

  • 确定非功能性需求。非功能性需求是指安全性、可用性、可扩展性等。

19

强制                

所有服务和批处理,都必须接入钉钉报警,和服务CAT监控。

设计文档类

1

强制                

存储方案和底层数据结构的设计获得评审一致通过,并沉淀成为文档。

  • 说明: 有缺陷的底层数据结构容易导致系统风险上升,可扩展性下降,重构成本也会因历史数 据迁移和系统平滑过渡而陡然增加,所以,存储方案和数据结构需要认真地进行设计和评审, 生产环境提交执行后,需要进行 double check。

  • 正例: 评审内容包括存储介质选型、表结构设计能否满足技术方案、存取性能和存储空间能否 满足业务发展、表或字段之间的辩证关系、字段名称、字段类型、索引等;数据结构变更(如 在原有表中新增字段)也需要进行评审通过后上线。

2

强制                

在需求分析阶段,如果与系统交互的 User 超过一类并且相关的 User Case 超过 5 个, 使用用例图来表达更加清晰的结构化需求。
3

强制                

如果某个业务对象的状态超过 3 个,使用状态图来表达并且明确状态变化的各个触发 条件。

  • 说明: 状态图的核心是对象状态,首先明确对象有多少种状态,然后明确两两状态之间是否存 在直接转换关系,再明确触发状态转换的条件是什么。

4

强制                

如果系统中某个功能的调用链路上的涉及对象超过 3 个,使用时序图来表达并且明确 各调用环节的输入与输出。 说明:时序图反映了一系列对象间的交互与协作关系,清晰立体地反映系统的调用纵深链路。
5

推荐                

如果系统中模型类超过 5 个,并且存在复杂的依赖关系,使用类图来表达并且明确类 之间的关系。

  • 说明: 类图像建筑领域的施工图,如果搭平房,可能不需要,但如果建造蚂蚁 Z 空间大楼,肯 定需要详细的施工图。

6

推荐                

如果系统中超过 2 个对象之间存在协作关系,并且需要表示复杂的处理流程,使用活 动图来表示。

  • 说明: 活动图是流程图的扩展,增加了能够体现协作关系的对象泳道,支持表示并发等。

业务逻辑层

1

强制                

减少跨系统的交互,一个系统尽量只能CURD自己业务域的数据库,不要跨域去操作其他应用的数据。(低耦合高内聚)

2

强制                

尽量减少IO以及网络的访问,将多次的调用整合在一次操作中完成,尽量减少IO资源的浪费。考虑提供批量处理接口(考虑异步处理,或流式处理)
3

推荐                

系统间调用最好是只读,系统间的修改用事件或者消息来实现比较靠谱。
4

推荐                

强一致性在微服务架构下不合适,互联网公司一般采用的基于消息【本地消息或者消息微服务;开源的消息中间件只是投递工具】的最终一致性事务的解决方案。
5

推荐                

系统需要有区分主次功能,对于主要功能需要加日志层面或者监控层面的告警逻辑;比如资金变动。

数据访问层

1

强制                

获取信息列表,必须使用分页处理 (需考虑将来数据增长)

注: 可以更具实际使用情况对分页参数设置默认值(20,50,100),保证有效的返回参数

2

强制                

禁止在操作数据库或者外部接口时候放在循环里面,尽量做成批量接口调用。
3

强制                

底层数据库以及上层应用本身都需要支持扩展来满足未来业务的增长需求。
4

强制                

更新处理只能使用主键或者唯一索引字段更新。
5

强制                

禁止使用insert .... select....
6

强制                

数据库字段长度和非空等在落库前校验;            
7

强制                

避免因事务过大而导致锁表锁行            
8

强制                

SQL必须要提供执行计划,防止全表扫描而导致查询效率低或数据库崩溃。            
9

强制                

数据库更新影响行数校验,防止因为缺少条件错误更新数据            
10

推荐                

对于数据库字段修改,或者其他显示复杂逻辑修改;尽量采用增加的操作;而少采用update的操作;update永远比insert成本大的很多。

3. 安全规约

接口层

1

强制                

安全准则第一条,永远不要相信用户的输入是安全的!用户请求传入的任何参数必须做有效性验证。

  • 说明: 忽略参数校验可能导致:

    1. 反例:某Web页面的url里面带有userid的参数,可以通过修改userid查看甚至删除该用户的数据

    2. 正例:通过服务器端的Session机制(或者redis)保存的当前会话用户经过认证(比如登录时通过userid和password认证后)的身份信息,使用服务器端保存的用户身份信息对用户操作进行鉴权,不能相信用户随意提交未经过认证的userid等身份信息,比如有允许用户修改个人地址的操作通过以下SQL来进行的时候,这里的userid应该使用保存在session中的userid,而不要使用用户任意提交的userid
       select/update... where addressID=#addressID# and ownerId=#userId#  

    1. 伪造其他用户的请求

    2. SQL注入

    3. XSS脚本注入

    4. 服务器命令脚本注入

    5. page size 过大导致内存溢出

    6. 恶意 order by 导致数据库慢查询  任意重定向

    7. 反序列化注入

    8. 正则输入源串拒绝服务 ReDoS,Java 代码用正则来验证客户端的输入,有些正则写法验证普通用户输入没有问题, 但是如果攻击人员使用的是特殊构造的字符串来验证,有可能导致死循环的结果。

2

强制                

隶属于用户个人的页面或者功能必须进行权限控制校验。

  • 说明:防止没有做水平权限校验就可随意访问、修改、删除别人的数据,比如查看他人的私信 内容、修改他人的订单。


               

请在查询或者修改数据的时候添加用户权限

示例:select/update... where addressID=#addressID# and ownerId=#userId#                

3

强制                

用户敏感数据禁止直接展示,必须对展示数据进行脱敏。

  • 说明:中国大陆个人手机号码显示为:158****9119,隐藏中间 4 位,防止隐私泄露。

注:此处最好是在服务端做数据处理

4

强制                

用户输入的 SQL 参数严格使用参数绑定或者 METADATA 字段值限定,防止 SQL 注入, 禁止字符串拼接 SQL 访问数据库。

注:

  1.   避免拼接SQL语句

5

强制                

禁止向 HTML 页面输出未经安全过滤或未正确转义的用户数据。

注:

  1.  string 类型字段要经过处理 null => ""

  2.  number/decimal 类型字段 要经过小数格式化处理

6

强制                

表单、AJAX 提交必须执行 CSRF 安全验证(原站One Time Token校验)。

  • 说明: CSRF(Cross-site request forgery)跨站请求伪造是一类常见编程漏洞。对于存在 CSRF 漏洞的应用/网站,攻击者可以事先构造好 URL,只要受害者用户一访问,后台便在用户 不知情的情况下对数据库中用户参数进行相应修改。

业务逻辑层

1

强制                

在使用平台资源,譬如短信、邮件、电话、下单、支付,必须实现正确的防重放的机 制,如数量限制、疲劳度控制、验证码校验,避免被滥刷而导致资损。

  • 说明: 如注册时发送验证码到手机,如果没有限制次数和频率,那么可以利用此功能骚扰到其 它用户,并造成短信平台资源浪费。

2

推荐                

发贴、评论、发送即时消息等用户生成内容的场景必须实现防刷、文本内容违禁词过 滤等风控策略。

4. 批处理

1

强制                

任务调度由任务本身(或者主任务)来控制,不要依赖系统默认的时间调度机制

2

强制                

需要支持多种触发机制(时间触发,事件触发,甚至API触发,指定对象主键触发强制处理等)

3

强制                

原则上要支持分布式并发处理,并且幂等(可以被反复执行)

4

强制                

要支持优雅结束(shutdown hooks)

5

强制                

要有死活监控(包括发现实际被挂起无响应的进程),报警以及主动恢复现场和断点续传的功能

6

强制                

数据要做到分批处理。禁止加载所有数据在内存中处理,单个批次的数据量要有限制。
7

强制                

日志中需记录处理件数(成功,失败)
8

强制                

Job需建立单独服务,可独立部署,不能和其他API服务耦合在一起。包括Batch, MQ消费Worker。

5. MySQL 数据库

推荐MySQL红宝书必学资料:高性能mysql第三版(on the Sharepoint),详见附件

建表规约

1

强制                

表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint (表示是,表示否)。                

  • 说明:任何字段如果为非负数,必须是 unsigned

  • 注意:POJO 类中的任何布尔类型的变量,都不要加 is 前缀,所以,需要在<resultMap>设置 从 is_xxx 到 Xxx 的映射关系。数据库表示是与否的值,使用 tinyint 类型,坚持 is_xxx 的 命名方式是为了明确其取值含义与取值范围。

  • 正例:表达逻辑删除的字段名 is_deleted表示删除,表示未删除。

2

强制                

表名、字段名必须使用小写字母或数字禁止出现数字开头,禁止两个下划线中间只 出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。                

  • 说明:MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。因此,数据库名、 表名、字段名,都不允许出现任何大写字母,避免节外生枝。

  • 正例:aliyun_adminrdc_configlevel3_name

  • 反例:AliyunAdminrdcConfiglevel_3_name

3

强制                

表名不使用复数名词。

  • 说明:表名应该仅仅表示表里面的实体内容,不应该表示实体数量,对应于 DO 类名也是单数 形式,符合表达习惯。

4

强制                

禁用保留字,如 descrangematchdelayed 等,请参考 MySQL 官方保留字。            
5

强制                

主键索引名为 pk_字段名;唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。                

  • 说明:pk_ 即 primary key;uk即 unique key;idx即 index 的简称。

6

强制                

小数类型为 decimal,禁止使用 float 和 double                

  • 说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不 正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。

7

强制                

如果存储的字符串长度几乎相等,使用 char 定长字符串类型。            
8

强制                

varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长 度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索 引效率。            
9

强制                

表必备三字段:id, create_time, update_time                

  • 说明:其中id必为主键,类型为bigint unsigned、单表时自增、步长为1。create_time, update_time 的类型均为 datetime 类型,前者现在时表示主动创建,后者过去分词表示被 动更新。

注:                

 update_time 默认值: CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)                

create_time 默认值: CURRENT_TIMESTAMP(6)                

10

强制                

单表索引不能超过5个。
11

推荐                

表的命名最好是加上业务名称_表的作用                

  • 正例:alipay_task force_project trade_config

12

推荐                

库名与应用名称尽量一致。
13

推荐                

如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。
14

推荐                

字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循:

  1. 不是频繁修改的字段。

  2. 不是 varchar 超长字段,更不能是 text 字段。

  • 正例:商品类目名称使用频率高,字段长度短,名称基本一成不变,可在相关联的表中冗余存 储类目名称,避免关联查询。

15

推荐                

单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。                

  • 说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。

16

参考                

合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检 索速度。

  • 正例:如下表,其中无符号值可以避免误存负数,且扩大了表示范围。

对象年龄区间类型字节表示范围人150 岁之内tinyint unsigned1无符号值:0 到 255龟数百岁smallint unsigned2无符号值:0 到 65535恐龙化石数千万年int unsigned4无符号值:0 到约 42.9 亿太阳约 50 亿年bigint unsigned8无符号值:0 到约 10 的 19 次方

17

强制                

所有数据表不可以物理删除,只能逻辑删除
18

强制                

金额字段的类型定义。  无精度要求时,定义为decimal(14, 2) ;  有精度需求时,定义为decimal(21, 9)

索引规约

注: explain type类型 ALL < index < range < ref < eq_ref < const < system < null


以下测试用表: 


create table tbl_member (
  id varchar(32),
  a varchar(32),
  b varchar(32),
  c varchar(32),
  d int(11),
  primary key (id)
);

create table tbl_order (
  id varchar(32),
  a varchar(32),
  b varchar(32),
  c varchar(32),
  d int(11),
  primary key (id)
);


当where条件作用在非索引字段的时候,type=ALL(全表扫描),所以常用的查询尽量采用索引来提高查询效率

%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-07-22%20%E4%B8%8B%E5%8D%889.29.21 (1).png



%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-07-23%20%E4%B8%8A%E5%8D%888.42.04.png

1

强制                

业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。                

  • 说明: 不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明 显的;另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必 然有脏数据产生。

2

强制                


3

强制                

在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度即可。                

  • 说明: 索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%以上,可以使用 count(distinct left(列名索引长度))/count(*)的区分度 来确定。

4

强制                

页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。                

  • 说明: 索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索 引。


               

下面是使用like的几种方式对比

  1. 单独使用 like 不管是 作用在 索引字段还是非索引字段 效果都不好

  2. 要使用 like 请配合一个索引字段,相当于缩小了数据范围,在其他字段上面使用 like,图中最后一个例子

undefined                


               

5

推荐                

如果有 order by 的场景,请注意利用索引的有序性order by 最后的字段是组合 索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。 正例:where a=? and b=? order by c; 索引:a_b_c                

  • 反例: 索引中有范围查找,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b; 索引 a_无法排序。

正确使用的案例:                

下面是正确的使用顺序, 注意:组合索引在 where 处可以不考虑顺序, MySQL 已经做过优化,但是在 order by 必须是 索引的顺序,                

%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-07-23%20%E4%B8%8A%E5%8D%887.56.27.png                


               

字段顺序使用对比:                

%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-07-23%20%E4%B8%8A%E5%8D%888.03.05.png                


               

看一个常见的情况:                

 这里 使用条件 a='a' and b > 'b' order by c, 有常量相当, 有比较大小,还需要排序,通常是常量字段和排序字段组成索引,其他中组合都会产生 filesort                

%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-07-23%20%E4%B8%8A%E5%8D%888.21.01 (1).png                


               

下面是个反例,还是使用 a 和 c 的 组合索引, 下面的例子会产生 filesort,而且like 还会产生 type=ALL                

%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-07-23%20%E4%B8%8A%E5%8D%888.26.56.png                


               

6

推荐                

利用覆盖索引来进行查询操作,避免回表。

  • 说明: 如果一本书需要知道第 11 章是什么标题,会翻开第 11 章对应的那一页吗?目录浏览 一下就好,这个目录就是起到覆盖索引的作用。

  • 正例:能够建立索引的种类分为主键索引、唯一索引、普通索引三种,而覆盖索引只是一种查 询的一种效果,用explain的结果,extra列会出现:using index

7

推荐                

利用延迟关联或者子查询优化超多分页场景。                

  • 说明: MySQL 并不是跳过 offset 行,而是取 offset+行,然后返回放弃前 offset 行,返回 行,那当 offset 特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过 特定阈值的页数进行 SQL 改写。

  • 正例:先快速定位需要获取的 id 段,然后再关联: 
    SELECT a.* FROM 表 1 a, (select id from 表 1 where 条件 LIMIT 100000,20 ) b where a.id=b.id

分页查询数据测试(字段数据少,返回条数少)随着数量的增多耗时在不断增加,                

  1. 数据量不超过一百万的时候,可以通过测试SQL语句测试时间

  2. 过数据量超过一百万以上,必须要优化SQL语句

%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-07-24%20%E4%B8%8A%E5%8D%888.12.11.png                


               

五十万数据的查询对比

%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-07-24%20%E4%B8%8A%E5%8D%888.20.02.png                

一百五十万的数据查询对比

%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-07-24%20%E4%B8%8A%E5%8D%888.26.14.png                


               


               

8

推荐                

SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好。                

  • 说明: 

    1. consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。

    2. ref 指的是使用普通的索引(normal index)

    3. range 对索引进行范围检索。

  • 反例: explain 表的结果,type=index,索引物理文件全扫描,速度非常慢,这个 index 级 别比较 range 还低,与全表扫描是小巫见大巫。

9

推荐                

建组合索引的时候,区分度最高的在最左边。

  • 正例: 如果 where a=? and b=? ,如果 列的几乎接近于唯一值,那么只需要单建 idx_索引即可。

  • 说明:存在非等号和等号混合时,在建索引时,请把等号条件的列前置。如:where c>? and d=? 那么即使 的区分度更高,也必须把 放在索引的最前列,即索引 idx_d_c

10

推荐                

防止因字段类型不同造成的隐式转换,导致索引失效。


               

因为数据类型转变(int → varchar),导致索引失效

undefined                


               


               

11

参考                

创建索引时避免有如下极端误解:                

  • 宁滥勿缺。认为一个查询就需要建一个索引。

  • 宁缺勿滥。认为索引会消耗空间、严重拖慢更新和新增速度。

  • 抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。


很赞哦! (0)