阿里分析型数据库AnalyticDB优化点

  • Post author:
  • Post category:其他


参考官方文档地址:

https://help.aliyun.com/document_detail/98793.html


由于工作中有用到AnalyticDB,只有很好的了解AnalyticDB才能做好优化工作!有些优化点跟MySQL差不多,只是多了分布式的特性,结合工作的应用自己总结了以下几个点:



1.SQL编写能简单尽量简单,比如单表查询肯定优于多表级联和子查询。



2.尽量不要用select *,即没必要返回不需要的列。



3.当SQL包含多个查询条件时,优先选择高筛选条件,其他条件可以通过扫描实现。

这是因为AnalyticDB内部采用列存方式,通过单列高效过滤后,可直接通过内部记录指针扫描其他列值,减少其他列的索引查询开销。

例如:


time条件通过内部扫描


Hint表示强制time>=’2010-01-01 00:00:00’条件走扫描。

/* +no-index=[tab1.time] */	
select c1,c2 from tab1 where c1=3 and time >='2010-01-01 00:00:00';

首先通过c1=3的条件可以快速定位到相关的数据,因此c1走索引。如果单独使用“time >=‘2010-01-01 00:00:00’”条件的话返回的记录数非常大,这时候跟据AnalyticDB的特性,time没必要走索引了。

计算引擎首先检索列c1的索引,得出满足条件c1=3的行集合,然后读取每行所对应的time列数据。如果满足time>=‘2010-01-01 00:00:00’,则将该行数据加入返回结果。


不等于条件通过内部扫描

增加no-indexHint,使不等于条件通过内部扫描执行,SQL示例如下:

/* +no-index=[tab1.c2] */
select c1,c2 from tab1 where c1=3 and c2<>100;


like条件通过内部扫描

中缀或后缀查询,例如:like ‘%abc’或like ‘%abc%’。

增加no-indexHint,使like条件通过内部扫描执行,更加快速地查询有效记录,SQL示例如下:

/* +no-index=[tab1.c3] */

select c1,c2 from tab1 where c1=3 and c3 like ‘%abc%’;



4.避免索引失效,应该尽量避免下面这些情况导致索引失效:

  • 函数转换(列)
  • 类型转换
  • like条件,例如:like ‘%abc%’



5.去掉不必要的is not null条件判断。



6.尽量不用子查询,如果可以的话改成表关联查询。

处理带有子查询的Select时,AnalyticDB首先执行子查询,并将子查询的结果保存在内存中,然后将该子查询作为一个逻辑表,执行条件筛选。

由于子查询没有索引,所有条件筛选都要进行扫描。因此如果子查询结果较大时,性能比较差。反之当子查询结果集较小时,扫描性能会超过索引查询。

对于join查询,由于AnalyticDB默认采用hash join算法,如果其中一张表结果集(条件筛选后)较大时,扫描性能会必索引差很多,因此尽量不要采子查询。例如以下SQL:

Select A.id from table1 A join
(select table2.id from table2 where table2.y = 6) B
on A.id= B.id where A.x=5

当满足条件x=5 和y=6的条数较多时,应改成:

Select A.id from table1 A join table2 B
on A.id = B.id
where B.y = 6 and A.x=5



7.多表关联

  • 普通表join普通表,尽量包含分区列join条件,如果不包含则,尽量通过where条件过滤掉多余的数据。

  • 维度表join普通表,没有限制。

多表关联查询where条件中,需要明确写明每一个表的过滤条件。通常我们在传统数据库中,都是通过索引字段关联来快速检索数据。如下SQL:

Select count(*) 
from customer_table C join 
order_table O on C.customer_id= O.customer_id
where O.order_time between'2018-07-20 10:00:11' 
and '2018-09-30 10:00:11' 
and O.order_amount=100;

在明确t2与t1表都有同样的time和type过滤条件情况下,建议修改为如下SQL:

Select count(*)
from t1 join t2 on t1.id=t2.id
where t1.time between '2017-12-10 00:00:00' and '2017-12-10 23:59:59'
and t1.type= 100
and t2.time between '2017-12-10 00:00:00' and '2017-12-10 23:59:59'
and t2.type=100



8.合理的使用一级分区,如果数据量非常大可以考虑二级分区。

AnalyticDB

一级分区表采用HASH分区

,可指定任意一列(不支持多列)作为分区列。HASH分区通过标准CRC算法计算出CRC值,并将CRC值与分区数作模计算,得出每条记录的分区号。空值的HASH值与字符串-1相同。以下按照优先级从高到底列出一级分区列的选择依据。

1.选择值分布均匀的列作为分区列,请勿选择分布不均匀的列作为分区列。

2.建议选择一级分区列的数据类型为tinyint、smallint、int、bigint或者varchar。

3.如果是多个普通表(不包括维度表)JOIN,则选择参与JOIN的列作为分区列。

如果是多列JOIN ,则根据查询重要程度或查询性能要求(例如:某SQL的查询频率特别高)来选择分区列,以保证基于分区列的JOIN具有较好的查询性能。

4.选择GROUP BY或DISTINCT包含的列作为分区列。

5.如果常用的SQL包含某列的等值或IN查询条件,则选择该列作为分区列。以下列子则选择id作为分区列。

 select * from table where id=123 and …;
 select * from table where user in(1, 2,3);



9.使用聚合列,使用的条件如下:

  • 主要或大多数的查询条件中均包括某一列,且该查询条件具有较高的筛选率,则选择该列作为聚集列。

  • Join子句中的等值条件列(通常是一级分区列)作为聚集列。