某种程度上,数据库调优十分考验一个工程师的技术功底和经验积累。
在调优之前,首先要明白,日常开发中,我们并不是随时都在做数据库调优,为了调优而调优就好像“为了追求设计而设计”一样不可取,那么何时知道需要做调优了呢?
1.用户的反馈
用户是产品的使用者,对于体验有最直观的感受,通过用户反馈发现问题,是特别常见的情形。
2.日志分析
可以通过查看数据库日志和操作系统日志等方式找出异常情况,通过它们来定位遇到的问题。
3.服务器资源使用监控
通过监控服务器的 CPU、内存、I/O 等使用情况,可以实时了解服务器的性能使用,与历史情况进行对比。
4.数据库内部状况监控
在数据库的监控中,活动会话(Active Session)监控是一个重要的指标。通过它,可以清楚地了解数据库当前是否处于非常繁忙的状态,是否存在 SQL 堆积等。
对数据库进行调优,都有哪些维度可以进行选择?
1.选择适合的 DBMS
数据库总体分为SQL 阵营和 NoSQL 阵营。
SQL 阵营常用的有 Oracle,SQL Server 和 MySQL 等。商业的数据库产品在事务处理和查询性能上都比较强,比如采用 SQL Server,那么单表存储上亿条数据是没有问题的。如果数据表设计得好,即使不采用分库分表的方式,查询效率也不差。
NoSQL 阵营包括键值型数据库、文档型数据库、搜索引擎、列式存储和图形数据库。这些数据库的优缺点和使用场景各有不同,比如列式存储数据库可以大幅度降低系统的 I/O,适合于分布式文件系统和 OLAP,但如果数据需要频繁地增删改,那么列式存储就不太适用了。
2.优化表设计
选择了 DBMS 之后,我们就需要进行表设计了。RDBMS 中,每个对象都可以定义为一张表,表与表之间的关系代表了对象之间的关系。如果用的是 MySQL,我们还可以根据不同表的使用需求,选择不同的存储引擎。
有一些优化的原则可以参考:
1.表结构要尽量遵循第三范式的原则。这样可以让数据结构更加清晰规范,减少冗余字段,同时也减少了在更新,插入和删除数据时等异常情况的发生。
2.也可以采用反范式进行优化。反范式采用空间换时间的方式,通过增加冗余字段提高查询的效率。
3.表字段的数据类型选择,关系到了查询效率的高低以及存储空间的大小。一般来说,如果字段可以采用数值类型就不要采用字符类型;字符长度要尽可能设计得短一些。针对字符类型来说,当确定字符长度固定时,就可以采用 CHAR 类型;当长度不固定时,通常采用 VARCHAR 类型。
3.优化逻辑查询
SQL 查询优化,可以分为逻辑查询优化和物理查询优化。逻辑查询优化就是通过改变 SQL 语句的内容让 SQL 执行效率更高效,采用的方式是对 SQL 语句进行等价变换,对查询进行重写。
SQL 的查询重写包括了子查询优化、等价谓词重写、视图重写、条件简化、连接消除和嵌套连接消除等。
比如我们在EXISTS 子查询和 IN 子查询的时候,会根据小表驱动大表的原则选择适合的子查询。在 WHERE 子句中会尽量避免对字段进行函数运算,它们会让字段的索引失效。
4.优化物理查询
物理查询优化是将逻辑查询的内容变成可以被执行的物理操作符,从而为后续执行器的执行提供准备。它的核心是高效地建立索引,并通过这些索引来做各种优化。
知道索引不是万能的,以下需要注意。
1.如果数据重复度高,就不需要创建索引。通常在重复度超过 10% 的情况下,可以不创建这个字段的索引。
2.要注意索引列的位置对索引使用的影响。比如我们在 WHERE 子句中对索引字段进行了表达式的计算,会造成这个字段的索引失效。
3.要注意联合索引对索引使用的影响。我们在创建联合索引的时候会对多个字段创建索引,这时索引的顺序就很重要了。比如我们对字段 x, y, z 创建了索引,那么顺序是 (x,y,z) 还是 (z,y,x),在执行的时候就会存在差别。
4.要注意多个索引对索引使用的影响。索引不是越多越好,因为每个索引都需要存储空间,索引多也就意味着需要更多的存储空间。此外,过多的索引也会导致优化器在进行评估的时候增加了筛选出索引的计算时间,影响评估的效率。
5.查询优化器在对 SQL 语句进行等价变换之后,还需要根据数据表的索引情况和数据情况确定访问路径,这就决定了执行 SQL 时所需要消耗的资源。
物理查询优化是在确定了逻辑查询优化之后,采用物理优化技术(比如索引等),通过计算代价模型对各种可能的访问路径进行估算,从而找到执行方式中代价最小的作为执行计划。
5.使用 Redis 或 Memcached 作为缓存
除了可以对 SQL 本身进行优化以外,我们还可以请外援提升查询的效率。
如果我们将常用的数据直接放到内存中,就会大幅提升查询的效率。键值存储数据库是首选。
常用的键值存储数据库有 Redis 和 Memcached,它们都可以将数据存放到内存中。
从可靠性来说,Redis 支持持久化,可以让我们的数据保存在硬盘上,不过这样一来性能消耗也会比较大。而 Memcached 仅仅是内存存储,不支持持久化。
从支持的数据类型来说,Redis 比 Memcached 要多,它不仅支持 key-value 类型的数据,还支持 List,Set,Hash 等数据结构。 当我们有持久化需求或者是更高级的数据处理需求的时候,就可以使用 Redis。如果是简单的 key-value 存储,则可以使用 Memcached。
6.库级优化
库级优化是站在数据库的维度上进行的优化策略,
1.我们可以采用主从架构优化我们的读写策略。采用读写分离的方式降低主数据库的负载,比如用主数据库(master)完成写操作,用从数据库(slave)完成读操作。
2.我们还可以对数据库分库分表。当数据量级达到亿级以上时,有时候我们需要把一个数据库切成多份,放到不同的数据库服务器上,减少对单一数据库服务器的访问压力。如果你使用的是 MySQL,就可以使用 MySQL 自带的分区表功能,当然你也可以考虑自己做垂直切分和水平切分。
3.什么情况下做垂直切分,什么情况下做水平切分呢?
如果数据库中的数据表过多,可以采用垂直分库的方式,将关联的数据表部署在一个数据库上。
如果数据表中的列过多,可以采用垂直分表的方式,将数据表分拆成多张,把经常一起使用的列放到同一张表里。
如果数据表中的行过多,数据达到了亿级以上,可以考虑水平切分,将大的数据表分拆成不同的子表,每张表保持相同的表结构。
最后,一句话总结下,数据库调优可以从三个维度进行考虑。一是数据库的选择,二是 SQL 查询优化(逻辑查询优化和物理查询优化),三是突破单一数据库或表的瓶颈。
网友评论