
对ArgoDB 的 SQL 优化,必须能快速定位ArgoDB性能的瓶颈点,或快速找到 SQL 主要的开销所在。瓶颈点通常由性能最慢的设备形成,如下载时网络速度可能是瓶颈点,本地复制文件时硬盘可能是瓶颈点。
为了快速找到 SQL 的性能瓶颈点,用户需要对各种设备的性能数据有一些基本的认识,如千兆网络带宽是 1000Mbps(转换为 125 MB/s),万兆网络带宽是 10000Mbps(转换为 1250 MB/s 或 1.22 GB/s);硬盘转速为每分钟 7200/10000 转等。
下图数据展示了当前主流计算机性能指标:

根据ArgoDB数据库相关特性,每种硬件主要的工作内容,分别如下:
-
CPU 和内存
缓存数据访问、比较、排序、事务检测、SQL解析、函数或逻辑运算、JOIN、数据加解密、加解压等;
-
网络
结果或者 Shuffle 数据的传输、 SQL 请求、远程数据访问等;
-
硬盘
数据访问、数据写入、日志记录、外排序、数据 Shuffle 等。
因此对于 ArgoDB 的性能优化,主要从充分利用各个硬件性能的角度分析,尽量做到以下这四点:
-
减少数据访问(减少磁盘访问)
-
减少中间结果量(减少网络传输或磁盘访问)
-
减少交互次数(减少网络传输、减少调度开销)
-
改进算法,减少服务器CPU开销(减少CPU及内存开销)
另外,除了以上四点还应注意任务分配要均匀且大小适中。总体而言,优化的基本思想就是反复迭代,合理利用资源,综合平衡各种开销,以求达到最优效果。
减少数据扫描
对于分布式数据库,支撑用户 OLAP 分析类业务以及点查类业务时,为快速提升数据查询效率,常使用索引的方式,减少数据访问、提升访问速度。同时,ArgoDB 还提供了分区、分桶,MinMaxFilter、BloomFilter 以及 RowFilter 等过滤器来批量过滤数据。
通过把相似、相关或者相等的数据进行归类以减少查询搜索的范围或者基于列式存储的特性尽可能减少无关数据的读取。
减少数据返回
方法一:
建议提交的 SQL 语句仅返回需要的列。因为每列的提取都需要一个复杂的解析过程,并且占用很多内存,且实际应用中很少会用到表的所有列,所以在编写SQL语句时,用户最好仅要求返回需要的字段,以减少不必要的查询时间。例如,通过明确指定查询字段去除不必要的返回字段。
如果某用户提交了这样的语句:
SELECT * FROM product WHERE company_id = 456723 LIMIT 100;
复制
如果实际需要的只有 id、name 两个字段,语句建议写为:
SELECT id, name FROM product WHERE company_id = 456723 LIMIT 100;
复制
方法二:
另外如果有些查询只是为了判断某些条件是否成立,就更加没必要返回所有列、甚至所有行。
某个包含关联的语句,在优化调整前,EXISTS 内部返回了满足条件的所有字段值:
SELECT ... FROM <table_name_2 >WHERE ... EXISTS ( SELECT * FROM <table_name_1> WHERE <table_name_1>.<col1> = <table_name_2>.<col1> );
复制
“SELECT *” 和 “SELECT 1” 的区别在于,前者返回包括 NULL 的所有列和行的值,而后者对于符合条件的行返回 1。 对非关联子查询,甚至可以写为:
... EXISTS ( SELECT 1 FROM table_name LIMIT 1 );
复制
-
<table_name_1>.<col1> 和 <table_name_2>.<col1> 分别是外内表用于关联的列。
-
“LIMIT 1” 表示仅返回一行,这样的子查询内部就只返回一个标量 1。
减少交互次数
Batch DML
数据库访问框架一般都提供了批量提交的接口,JDBC 支持 Batch 的提交处理方法,当用户要一次性往一个表中插入 1000 万条数据时,如果采用普通的 Insert,将和服务器交互 1000 万次,按每秒钟向数据库服务器提交 10000 次估算,完成所有工作需要消耗 1000 秒。如果采用批量提交模式,每 1000 条提交一次,和服务器的交互次数就减少至 1 万次,交互次数大大减少。采用 Batch 操作虽然通常不会大量减少数据库服务器的物理 I/O,但是会大幅减少客户端与服务端的交互次数,从而降低多次发起的网络延时开销,以及数据库的 CPU 开销。
In List
有时会遇到这样的情况,有多个 ID,需要在数据库中查询这些 ID 代表的记录。可通过两种方式实现:单条提交或者批量提交。
-
单条处理就是采用一个 ID 发一个请求的方式传送给数据库:
for: var in ids[] do begin SELECT * FROM table_name WHERE id=:var; end;
复制这样的方法是不推荐的,因为会增加与服务器的交互次数。
-
建议用 ID In List 批量提交:
SELECT * FROM table_name WHERE id IN ids[];
复制这样就把多次交互压缩在一次访问中完成,加速任务的完成。
减少 CPU 运算
一般 SQL 中会包含各种各样的运算。进行计算时,对于不匹配的类型,要对操作数进行转换,导致 CPU 负担加重。所以,对于数字和日期类型,建议用户在执行计算前通过类型转换,使各操作数的类型匹配,或者建表时尽可能的把字段安排成相同的数据类型。
另外,SQL 业务逻辑中经常会包含一些比较运算符,如等于(a = b)、不等(a < b)等。ArgoDB 通常对普通比较运算符有较好的表现,但是对于服务器 CPU 需求量很高的操作,需要保持警惕。如 Like 模糊查询对 CPU 的要求一般较高,数据库并不擅长处理,特别是模糊检查的记录有上万条及以上时,系统表现比较糟糕。建议用户根据业务语义尽量用 In-List 实现 Like,In-List 中需包括所有可能的匹配选项。
SELECT * FROM table_name WHERE column_name LIKE ‘%abc%’;
复制
若已知该列字段值仅有三种取值 ‘cabc’、‘abce’、‘cabe’,上面的语句可以等价为这样的表达方式:
SELECT * FROM table_name WHERE column_name IN (‘cabc’, ‘abce’, ‘cabe’);
复制
如果 In-List 数据太多,可以让一张中间小表作为 In 列表内部数据,然后采用内外查询关联的方式进行检索。
SELECT COUNT(*) FROM Car WHERE car_no IN ( SELECT car_no FROM orders WHERE trans_date = ‘2014-03-15’ );
复制