可以优化的地方
(*)sql语句优化
(*)数据库优化(表结构,索引,视图,存储过程等等)
(*)垂直分表,水平分表
(*)业务逻辑优化
(*)缓存使用
(*)分布式数据库
(*)网络优化
(*)硬件优化,如磁盘,cpu,内存等。
选择合适的索引列
(*)查询频繁的列,在where,group by,order by,on从句中出现的列。
(*)where条件中<,<=,=,>,>=,between,in,以及like字符串+通配符(%)出现的列。
(*)长度小的列,索引字段越小越好,因为数据库的存储单位是页,一页中能存下的数据越多越好。
(*)离散度大(不同的值多)的列,放在联合索引前面。查看离散度,通过统计不同的列值来实现,count越大,离散程度越高。
SQL的编写需要注意优化
(*)尽量使用数字型字段
(*)任何地方都不要使用 select * from t;,用具体的字段列表代替“*”,不要返回用不到的任何字段。
(*)使用limit对查询结果的记录进行限定。
(*)使用连接(join)来代替子查询。
(*)可通过开启慢查询日志来找出较慢的SQL。
(*)不做列运算:SELECT id WHERE age + 1 = 10,任何对列的操作都将导致表扫描,它包括数据库教程函数、计算表达式等等,查询时要尽可能将操作移至等号右边。
(*)SQL语句尽可能简单:一条SQL只能在一个cpu运算;大语句拆小语句,减少锁时间;一条大SQL可以堵死整个库。
(*)OR改写成IN:OR的效率是n级别,IN的效率是log(n)级别,in的个数建议控制在200以内。
(*)尽量避免使用!=或<>操作符,否则数据库引擎会放弃使用索引而进行全表扫描。
(*)避免对字段进行null值判断。
(*)很多时候用exists代替in是一个好的选择。
(*)不用函数和触发器。
(*)在应用程序实现避免%xxx式查询。
(*)少用JOIN。
(*)能用UNION ALL就不要用UNION。UNION ALL不执行SELECT DISTINCT函数,这样就会减少很多不必要的资源。UNION ALL允许重复。
(*)使用同类型进行比较,比如用'123'和'123'比,123和123比。
(*)尽量避免在WHERE子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描对于连续数值,使用BETWEEN不用IN:SELECT id FROM t WHERE num BETWEEN 1 AND 5;。
(*)列表数据不要拿全表,要使用LIMIT来分页,每页数量也不要太大。
(*)对出现在where子句中的字段加索引。
(*)如果where语句中有多个字段,那么可以考虑创建组合索引。
(*)创建覆盖索引。覆盖索引(covering index,或称为索引覆盖)即从非主键索引中就能查到的记录,而不需要查询主键索引中的记录,避免了回表的产生减少了树的搜索次数,显著提升性能。
注意,遇到以下情况,执行计划不会选择覆盖查询:select选择的字段中含有不在索引中的字段 ,即索引没有覆盖全部的列;where条件中不能含有对索引进行like的操作。
垂直分表
定义:垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表(垂直拆分更多时候就应该在数据表设计之初就执行的步骤,然后查询的时候用jion关键起来即可)。
(1)把不常用的字段单独放在一张表。
(2)把text,blob等大字段拆分出来放在附表中。
(3)经常组合查询的列放在一张表中。
水平分表
定义:水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。
拆分方法:
(1)HASH取模
优点:能保证数据较均匀的分散落在不同的库、表中,减轻了数据库压力。
缺点:扩容麻烦、迁移数据时每次都需要重新计算hash值分配到不同的库和表。服务器数量变动的时候,所有数据存储的位置都要发生改变,例如3台服务器增加为5台时,除数由3变为了5,被除数不变的情况下,余数肯定不同。
(2)一致性HASH
优点: 通过虚拟节点方式能保证数据较均匀的分散落在不同的库、表中,并且新增、删除节点不影响其他节点的数据,高可用、容灾性强。
(3)部分业务逻辑也可以通过地区,年份等字段来进行拆分。
----------------------------------
求余取模(HASH取模):
(1)一张有400W的用户表users,为提高其查询效率我们把其分成4张表users1,users2,users3,users4。
(2)通过用ID取模的方法把数据分散到四张表内Id%4+1 = [1,2,3,4]。
(3)查询,更新,删除也是通过取模的方法来查询。
(4)获取自增id的第一种方法:创建临时表uid_temp,insert into uid_temp values('')。第二种方法:使用redis的incr操作。
(5)得到自增的ID后,又通过取模法进行分表插入。
(6)注意,进行水平拆分后的表,字段的列和类型和原表应该是相同的,但是要记得去掉auto_increment自增长。
$_GET['id'] = 17,
17%4 + 1 = 2,
$tableName = 'users'.'2'
Select * from users2 where id = 17;