数据库优化(三)表设计优化
SQL优化阶段主要是对索引的命中情况进行分析,而我们也知道SQL优化并不是万能的,在绝对的数据量情况下,SQL再怎么优化也终究逃不过慢的结局。所以我们就需要从设计层面去提供一些优化的思路,这里我们主要会介绍一些在索引、表结构上的设计优化,这些优化方式会具有一些场景性并不是万能的,但这些案例的思路是大家可以学习的。
索引设计
索引的重要性是不言而喻的,我们不仅要在查询的时候进行索引的调整,而是在设计阶段就要根据索引的特性来设计合适的索引,不合适的索引不仅没用反而有可能影响我们的SQL效率,在设计索引的时候我们要遵循一些原则,这会帮助我们能设计出高效的索引。
常用字段建立索引
经常要用于查询的列 where id=?。
经常要用于排序(order by),分组(group by)的列,因为索引已经排好序了。
有值唯一性限制的列,比如说主键、用户名。
大字段不适合建立索引
大字段上建立索引会直接导致我们的索引树变得庞大,因为索引树的节点大小是固定的,当字段越大那么每个索引树节点会变多,导致树层级变多,树的层级越多查询的效率就会越慢。而且数据库默认会把索引加载到内存里,大字段建立的索引会变得庞大,所以也会消耗更多的内存空间。
选择合适的字段长度
字段的大小会影响到几方面的东西,一是字段大会使表变大,二是字段大会使索引树变大并且层级变高,三是索引变大后又会消耗掉更大的内存。
离散性不高的字段不适合建立索引
离散性不高是指数据的区分度不高,比如性别,只有男和女,那么这种字段上建立索引就算命中了,那么每次扫描的时候还是需要扫描一半的数据,所以这种字段上建立索引并不能提升检索效率。
更新频繁的数据不适合建索引
索引本质也是数据库额外维护的一个数据结构,当我们的索引字段频繁变更,那势必也造成索引的结构频繁变更,频繁的数据维护和索引的变更维护会造成数据库性能的损耗。
多使用组合索引
在合适的业务场景下,我们可以多使用组合索引,Mysql的每次查询只会使用一个索引作为检索数据的依据,如果要让索引使用的更有效率,那么我们可以尽可能的让索引匹配出来的数据越少越好,也就是让我们的索引区分度更高,组合索引就能帮我们达到这一效果,比如我们需要寻找一个人,那么使用姓名+地区+年龄 找到数据显然是要比只使用姓名去查找出来的数据要少得多,而组合索引的功效就在于此,当然设计组合索引的时候不要忘了遵守“最左匹配原则”。
表设计优化
有时候数据库性能是无法单方面通过优化索引来达到性能的显著提升的,表数据量太大,联表查询数据太多都是索引解决不了的问题,这个时候我们就需要考虑到从业务层面对表结构进行一些设计和调整,反而是解决问题的关键。
字段冗余
字段冗余主要是减少我们的联表查询的操作,因为进行join 查询的时候,我们需要匹配的数据量是呈笛卡尔积的上升的,所以减少联表的操作有时候对效率有显著的提升。
场景:用户信息的关联查询
字段冗余的一个前提条件就是这个字段的值基本不会变,比如说:身份证、姓名、还有一些系统常量的配置分类等,这些字段基本上不会改变的,而这些信息往往在我们查询业务数据的时候同时也要查询出来,这个时候就不可避免的要进行join 用户表或系统表进行查询,通常像用户表这种数据量都比较大,所以join操作会成为数据库性能的瓶颈。
这种时候我们就可以使用字段冗余的方案,在需要查询的业务表里也冗余一个身份证、姓名这样的字段,在插入数据的时候就把对应的数据存入到对应的业务表中,那么查询的时候就不需要去进行表关联查询了。
表冗余
表冗余一般适合统计类的场景,比如说运营需要分析日报、周报、季报、年报等维度的数据,那么这个时候我们通常可以使用表冗余的思路。
场景:用户活跃度统计分析
拿用户登录数据分析来说,运营需要对用户最近登录的数据分析平台用户的活跃度,维度有日、周、月、季、年的统计数据。因为系统每天登录的用户可能会有几万至几百万的数据,那么一周、一月的数据很有可能就达到了几千万的数据,如果z这种情况我们还是通过SQL去统计这些数据,那么很显然是一件非常糟糕的事情。
这个时候就可以考虑表冗余的方式了,我们可以把数据以天为维度冗余一张统计表出来,这个表里面就保存平台每天登录的统计人数记录,然后用一个定时任务每天24点执行统计一次,把统计信息插入到此表,这样的话这个表的记录每天只会增加一条,运营需要统计数据的时候我们可以直接查询这张冗余表来得到数据,这种方式一年也就365条数据,效率将会是一个巨大的提升。
数据冷热分离
表数据的冷热分离思路就是根据业务场景来区分哪些数据是经常要用到的数据(热数据),哪些数据基本上不用到或者很少用到(冷数据),如果表数据具备这样的业务特性,那么我们可以采用数据冷热分离的方式对数据库进行优化。
场景:订单数据冷热分离。
平台订单每天上万,随着时间推移数据越来越多了,到了几百上千万的时候使用索引效率也非常慢了,而用户查询订单列表的功能也是一个常用且刚需的功能,这个时候我们就采用数据冷热分离的思路进行优化了。
首先分析业务场景,一般情况下用户只会查询最近一段时间下的订单,这个时间有可能就是你的一次订单周期,7天到一个月不等。而用户基本很少去查询一个月之前的订单数据,那么这个时候我们就可以根据业务场景了解到数据的特性了,我们此时就可以通过建立一张订单的备份表,然后把订单主表一个月之前的数据都存放到这个备份表里去,每天定时的把超过一个月时间的订单数据迁移到备份表,而订单主表只保存最近一个月的订单数据,那么就算订单量每天上万,一个月下来订单主表也只会有三十几万数据,这样用户查询订单列表的时候性能就会得到巨大的提升。
当然用户也有查询一个月之前数据的需求,这个时候就需要查询备份表了这个时候可能还是比较慢,但是考虑到用户使用这样的操作频率非常低,所以也还是可以接收的,当然你也可以对备份表进行一些优化,比如多备份几个维度的数据表,一个月、一个季度,一年的,根据用户自定义的时间去查询对应的表。