诊断性能问题 -------------- 当你发现查询性能问题的时候,可以从以下几个方面入手来加以诊断: * 检查集群的状态: 查看是不是有死掉的 HDFS DataNode 或者 OushuDB segment,方法如下: .. code-block:: html :linenos: # 检查是否有DataNode死掉,使用命令 hadoop dfsadmin -report # 检查是否有 OushuDB segment 死掉,可以使用语句查看: select * from oushu_cluster_status; * 检查节点上是不是有坏盘。查看硬件的性能是不是跟期待的一样。可以通过”oushudb checkperf”命令检查网络,磁盘速度。磁盘速度以及网络速度经常是问题所在。 * 查看Explain Analyze查询的结果,找出慢的操作,从而推测出问题的地方 .. code-block:: html :linenos: I. 有时候有些操作不能在内存中完成,比如HashJoin,HashAggregate, 这时候在Explain Analyze的输出中会看到产生的spill文件信息。 外存算法通常会比内存算法要慢很多。如下例所示: -> Hash Join (cost=7349612.80..1269920578.75 rows=16726776002 width=0) Hash Cond: b.d020 = a.d020 Rows out: Avg 26902546221.0 rows x 6 workers. Max/Last(seg0:hawq2/seg0:hawq2) 40017551225/40017551225 rows with 20528/20528 ms to first row, 4273919/4273919 ms to end, start offset by 28/28 ms. Executor memory: 450570K bytes avg, 450570K bytes max (seg5:hawq2). Work_mem used: 206760K bytes avg, 207884K bytes max (seg0:hawq2). Workfile: (6 spilling, 0 reused) Work_mem wanted: 1633616K bytes avg, 1638375K bytes max (seg4:hawq2) to lessen workfile I/O affecting 6 workers. (seg0) Initial batch 0: (seg0) Wrote 1003408K bytes to inner workfile. (seg0) Wrote 1805360K bytes to outer workfile. ... (seg4) Read 2006596K bytes from inner workfile: 286657K avg x 7 nonempty batches, 289127K max. (seg4) Read 3594787K bytes from outer workfile: 513541K avg x 7 nonempty batches, 527403K max. (seg4) Hash chain length 6.7 avg, 33890 max, using 6269397 of 16777688 buckets. 这时可以尝试通过改变资源队列来给分配更大的virtual segment来给查询更多的内存。有如下方法: .. code-block:: html :linenos: set statement_mem="2GB"; * 看一看优化器的估计值(例如输出行数)是不是接近真实值,如果不接近真实值,优化器可能产生不优化的查询计划。如果不接近真实值,需要查找原因,可能是该表在加载后没有analyze,也可能是统计数据不准。如果不准的话,可以通过下面的几个方法来改进统计数据收集的准确率,或者修改参数,或者调整查询 * 查看是否选择谓词被尽量下推到了查询计划的底层,如果查询计划没有很好的估计出谓词的选择率,可以通过analyze相关列来得到统计数据。也可以尝试调整where子句中的谓词顺序 * 看一看优化器有没有选择到最优的连接顺序。能够消除大量行的连接应该先执行,从而使得后面的连接可以处理少一些元组。如果优化器没有选出优化的顺序,尝试设置join_collapse_limit = 1,并且使用显式的连接语法来强制连接顺序。你也可以尝试收集更多的相关连接列的统计数据来帮助优化器做出更好选择。 * 尝试设置default_statistics_target到100或者更大的值,来得到更加精确的统计值 * 看一看优化器是不是选择了Hash聚集或者Hash连接,通常情况下,Hash聚集和Hash连接要比其他聚集和连接算法要快。让优化器去选择Hash聚集或者Hash连接,往往需要有足够的内存。可以尝试调整资源队列来给查询分配更多资源 * 如果我们使用Hash分布的表,查看分布是否产生了倾斜(skew),如果产生了倾斜,需要选取合适的Hash分布key。检查倾斜的方法为: .. code-block:: html :linenos: SELECT gp_segment_id, COUNT(*) FROM your_table_name GROUP BY gp_segment_id ORDER BY gp_segment_id; * 检查查询中涉及到的表是否通过Analyze收集过统计数据 * 检查数据局部性统计:查看是不是 data locality ratio 很低,如果低的话,需要找出具体原因。比如有可能是 HDFS 没有配置好等。检查HDFS有没有配置好可以查看 OushuDB segment 上的日志里面是不是产生了大量的 Exception。 * 检查查询及资源队列状态,看看查询是不是在等待资源,而不是真正在执行 .. code-block:: html :linenos: # pg_stat_activity视图给出了现在系统里面正在运行的所有查询及状态 select * from pg_stat_activity; # pg_resqueue_status视图给出了现在系统内部资源队列的状态 select * from pg_resqueue_status; * 检查是否产生了元数据膨胀(bloat)。OushuDB 针对元数据采用 Magma AP 格式存储,Mamga AP 格式存储采用了多版本(MVCC)机制。所以如果出现元数据表的频繁更改,比如频繁创建和删除表,而又长期没有对元数据表进行compact操作,元数据表可能出现膨胀,元数据表膨胀可能带来查询效率急剧下降,这是因为访问元数据的时间过长的缘故。检查膨胀的方法为,查看元数据表的行数X和该元数据表所有版本的行数BX,如果BX远大于X,则该表出现了膨胀。例如下面的例子检查到pg_class_internal表的BX为417,而X为369。 .. code-block:: html :linenos: postgres=# set gp_select_invisible=true; SET postgres=# select count(*) from pg_class_internal; count ------- 417 (1 row) postgres=# set gp_select_invisible=false; SET postgres=# select count(*) from pg_class_internal; count ------- 369 (1 row) 一般地,Magma 后台有一定数量的 compact 线程定期执行 compact 操作。如果发现元数据表出现了膨胀,解决办法为先做 compact 操作。对 OushuDB 的日常维护操作请参见 OushuDB 日常运维。 .. code-block:: html :linenos: postgres=# COMPACT FULL TABLE pg_class_internal; COMPACT FULL TABLE 如果一个表有SERIAL或者BIGSERIAL列(自增列),那么在加载数据时,master的Sequence Server往往会有瓶颈。那是因为所有的Segment会向Master节点的Sequence Server询问下一个值。每一个值都询问会带来很大瓶颈。可以使用下面语句使得Segment每次获取10000个值。 .. code-block:: html :linenos: postgres=# CREATE TABLE tname (colname BIGSERIAL); NOTICE: CREATE TABLE will create implicit sequence "tname_colname_seq" for serial column "tname.colname" CREATE TABLE postgres=# alter sequence tname_colname_seq cache 10000; ALTER SEQUENCE