
# TaurusDB索引设计规范
- 避免因为字段类型不同造成的隐式转换，导致索引失效。
- 业务上具有唯一特性的字段，即使是多个字段的组合，建议在所有具有唯一特性字段的最小集合上建立唯一索引。 同时需要考虑建立的唯一索引对查询是否真正有帮助，没有帮助的索引可以考虑删除。需要考虑多建立的索引对插入性能的影响，根据唯一性相关的数据正确性需求，以及性能需求来权衡是否需要多建立唯一性索引。
  例如：一个表含有a，b，c，d，e，f字段，在业务上a、b和e、f分别是具有唯一特性的字段集合，那么建议在最小集合a、b和e、f上分别建立唯一索引。
  ![](https://support.huaweicloud.com/usermanual-taurusdb/public_sys-resources/note_3.0-zh-cn.png)
  即使在应用层做了完善的校验控制，只要没有唯一索引，根据墨菲定律，必然有脏数据产生。
  
- 尽量在定长的字段（如：INT）上建立索引；在VARCHAR字段上建立索引时，必须指定索引长度，无需对全字段建立索引，根据实际文本区分度决定索引长度即可。
  ![](https://support.huaweicloud.com/usermanual-taurusdb/public_sys-resources/caution_3.0-zh-cn.png)
  索引长度与区分度是一对矛盾体，一般对字符串类型数据，长度为20的索引区分度会高达90%以上，可以使用COUNT(DISTINCT LEFT(列名，索引长度))/COUNT(\*)的区分度来确定。（有区分度的放前面，没有区分度的放后面）。
  
- 页面搜索避免使用左模糊（如：SELECT \* FROM users WHERE u_name LIKE '%hk'）或者全模糊，避免从索引扫描切换为全表扫描，如果需要请在应用层解决。 索引文件具有B-tree的最左前缀匹配特性，如果左边的值未确定，那么无法使用此索引。
  
- 利用覆盖索引来进行查询操作，避免回表，但是覆盖索引加的字段不能太多，要兼顾写性能。 能够建立索引的种类：主键索引、唯一索引、普通索引，而覆盖索引是一种查询的效果，利用explain的结果，extra列会出现：using index。
  
- SQL性能优化的目标：至少要达到range级别，要求是ref级别，如果可以是consts最好。
- 创建组合索引的时候，区分度最高的在左边。
- 单张表的索引数量控制在5个以内，或不超过表字段个数的20%。
- 创建索引避免有如下误解：
  - 宁滥勿缺。误认为一个查询就需要建一个索引。
  
  - 宁缺勿滥。误认为索引会消耗空间、严重拖慢更新和新增速度。
  
  - 抵制唯一索引。误认为业务的唯一性一律需要在应用层通过"先查后插"方式能解决。
   
- 根据实际业务需求，减少使用无法利用索引优化的order by查询语句。Order by、group by、distinct这些语句较为耗费CPU资源。
- 涉及到复杂SQL语句时，优先参考已有索引进行设计，通过执行explain，查看执行计划，利用索引，增加更多查询限制条件。
- 使用新的SELECT、UPDATE、DELETE语句时，都需要通过**explain** 查看执行计划中的索引使用情况，尽量避免extra列出现Using File Sort或Using Temporary。当执行计划中扫描的行数超过1000时，需要评估是否允许上线。需每日进行慢日志统计分析，处理慢日志语句。执行计划的详细参数解释请参见[表1]。
   表1explain参数说明 
  | 参数            | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
  |:---|:---|
  | type          | 扫描类型。 - ALL：全表扫描。  - index：索引扫描。  - range：索引范围扫描。  - ref：使用普通索引进行等值匹配。  - eq_ref：使用主键（PRIMARY KEY）或 唯一索引（UNIQUE INDEX）进行等值匹配。  - const：当查询通过主键（PRIMARY KEY）或唯一索引（UNIQUE INDEX）进行等值匹配（=）时，MySQL能直接定位到唯一一行数据。  - system：表只有一行数据。  - NULL：查询不需要访问表即可完成。   |
  | possible_keys | 指出MySQL在查询过程中可能使用到的索引。查询涉及到的字段上若存在索引，则该索引将被列出，但不一定被查询使用。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
  | key           | 表示MySQL实际决定使用的键（索引），如果没有选择索引，键是NULL。如果想强制MySQL使用或忽视possible_keys列中的索引，在查询中使用FORCE INDEX、USE INDEX 或者IGNORE INDEX。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
  | ref           | 哪些列或常量被用于查找索引列上的值。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
  | rows          | 根据表统计信息及索引选用情况，估算的找到所需的记录所需要读取的行数。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
  | Extra         | - Using temporary：表示MySQL需要使用临时表来存储结果集，常见于排序和分组查询。  - Using filesort：MySQL中无法利用索引完成的排序操作称为"文件排序"。  - Using index：表示使用索引，如果只有 Using index，说明没有查询到数据表，只用索引表即完成了这个查询，这种情况为覆盖索引。如果同时出现Using where，代表使用索引来查找读取记录， 也是可以用到索引的，但是需要查询到数据表。  - Using where：表示条件查询，如果不读取表的所有数据，或不是仅仅通过索引就可以获取所有需要的数据，则会出现 Using where。如果type列是ALL或index，而没有出现该信息，则你有可能在执行错误的查询，返回所有数据。                                                                                                                                                                                                                                                                                                                             |
     
  
- 在WHERE条件列上使用函数，会导致索引失效。 示例：如 WHERE left(name, 5) = 'zhang'，left函数会导致name上的索引失效。
  修改方案：可在业务侧修改该条件，不使用函数。当返回结果集较小时，业务侧过滤满足条件的行。
  
- 对于超大表，在索引使用上还需要遵循以下规范。
  - 要根据查询有针对性地创建，考虑在WHERE和ORDER BY命令上涉及的列建立索引，可根据EXPLAIN来查看是否用了索引还是全表扫描。
  
  - 值分布很稀少的字段不适合建索引，例如"性别"这种只有两三个值的字段。
  
  - 字符字段不要做主键。
  
  - 不用外键，由程序保证约束。
  
  - 使用多列索引时注意顺序和查询条件保持一致，同时删除不必要的单列索引。
  
  - 删除索引，要做充分论证，最好做数据备份。
  
  - 对于千万或亿级大数据量的表，参考[对于千万或亿级的超大表如何高效创建索引](https://support.huaweicloud.com/taurusdb_faq/taurusdb_faq_0300.html)提升创建索引效率。
   
 
