关于数据库优化的一些想法

优化table结构redis

#1 列数据类型尽可能使用数字类型,避免使用字符类型,后者不只会占用较多存储空间并且会下降查询效率(逐字符比较);算法

#2 优先使用VARCHAR,变长字段存储空间小,还能够提高查询效率;sql

#3 对须要常常做为where条件出现的column添加索引,经过添加constraint设置为unique key(自动添加索引);缓存

#4 对于单DB而言,primary key使用AUTO_INCREMENT的BIGINT是最合适的,自增类型的ID便于分页和索引(UUID的key具备无序性,并且字符类型耗费资源);对于DB集群而言,以DB自身的算法生成ID不能保证惟一性,因此须要引入一个全局的ID generator保证惟一性的同时提供较好的性能,Redis和ZooKeeper是比较好的选择;另外经过给不一样的DB或者App加入一个惟一的SN也能最大程度保证惟一性。架构


优化SQL语句并发

#1 对于查询语句尽可能添加NO_LOCK标志,提高DB并发量;分布式

#2 筛选条件放置位置按优先级从高到低依次为on, where, having,越到后面须要保存的数据和进行的计算就越多:memcached

#3 在where子句中避免使用[!=, <>, or, in, not in, %, like, is null, is not null],缘由是会致使DB引擎放弃使用index而进行全文扫描,推荐使用exist或者not exist;高并发

#4 若是某列的重复数据较多,则index不能发挥较好的性能,反而过多的索引还会下降insert和update的效率;性能

#5 对于涉及多张表的联合查询,依次将数据量最小的表按从右到左的顺序放置,保证中间虚拟表只包含最少的数据;

#6 DB引擎解析一条SQL语句的流程

1 [8] SELECT [9] DISTINCT [11] TOP # <column list>
2 [1]   FROM <left table> [3] <join type> JOIN <right table> [2] ON <join condition>
3 [4]   WHERE <where condition>
4 [5]   GROUP BY <group by list>
5 [6]   WITH <CUBE | ROLLUP>
6 [7]   HAVING <having condition>
7 [10]  ORDER BY <order by list>;


对于sql中每个子句都会生成一张virtual table用于存储中间数据,所以须要尽量的减小每一步中VT的数据,上述SQL语句的执行顺序以下:
【1-3】:FROM子句中若是只有一张表,则不作任何处理;若是有两张表,则对其作笛卡尔积处理生成VT1;而后根据join condition执行ON子句进行筛选并生成VT2;接着根据join type(LEFT, RIGHT, INNER, OUTTER)执行JOIN子句生成VT3;若是有超过两张表,则依次处理完前两张表以后在VT3的基础上继续处理以后的表,直到全部的表都处理完最终生成VT4;SQL解释器通常按照从右到左的顺序处理表,所以须要保证越是靠右的表的数据量是越少的。
【4】:根据where condition执行WHERE子句,对中间表数据进行筛选并生成VT5。
【5】:根据group by list执行GROUP子句,对中间表进行分组并生成VT6。
【6】:根据CUBE仍是ROLLUP执行WITH子句,对分组结果进行汇总并生成VT7。
【7】:根据having condition执行HAVING子句,对分组结果进行筛选并生成VT8。
【8】:根据column list执行SELECT子句,对中间表进行数据映射并生成VT9。
【9】:执行DISTINCT子句,将重复的行从表中去除并生成VT10。
【10】:根据order by list执行ORDER BY子句,对中间表进行排序并生成VT11。
【11】:根据#(数量或者比例)执行TOP子句,从中间表中去除相应数据量结果并生成VT12。

按期查看SQL执行status

SQL server profiler,须要按期查看DB中超过某个执行时间限制的, 或者是资源占用率超过某些限制的SQL语句;

读写分离

对于单库DB设计而言,若是读写请求同时操做一个库,势必极大的下降DB性能;而通常状况读操做远远多于写操做,这时候就能够经过master-slave的设计,将同一个库的数据作多个备份,写操做仅针对master进行,读操做在master和salve均可以进行;master按期将自身的数据更新到slave上,保证数据的最终一致性同时提高DB的QPS。


分库分表

对于单库多表而言,业务相关的数据尽可能放置于同一个库1里面(垂直切分,业务拆分),好比用户A支付B元购买了C商品寄送到D地址,这样能够保证较好的读取性能,这样也能将事务限制在一个库的范围内;可是当库1的某张表的数据记录超过某个限制(单库单表数据量在800万条之内具备比较好的读写性能),须要另起一个库2放置新增长的各个表的数据(水平切分),库1和库2具备相同的表组成,数据量增加的时候也以此类推,以后新的业务数据须要访问和操做某个库时,须要根据某种映射算法(key % n)选择对应的库进行数据读写,这个key必须是知足分布式ID的全局惟一性;

在异地多活中心的架构中,分库的设计能够解决高并发访问的问题,好比有100个手机库存,若是放到一个库里,则全部并发都须要竞争同一把锁,但若是将100个手机库存平均分配到4个库里,每一个库有25个库存,则并发访问能够同时竞争四把锁,极大提高了并发效率;另一种设计是将100个手机库存维护在一个DB库中,但使用redis等缓存基于窗口机制一次性获取多个库存到缓存中,好比redis-01预获取0-24号库存,则更新DB库存为75,redis-02预获取25-49库存,则更新DB库存为50,这样的设计能够减小较慢的DB锁的竞争,而使用较快的cache锁的竞争替代。

使用cache替代DB检索

使用redis或者memcached做为数据缓存

相关文章
相关标签/搜索