这是本节的多页打印视图。
点击此处打印.
返回本页常规视图.
对数据库性能执行分析
可以分析数据库操作以评估性能。分析可以提供如下信息:
分析数据有助于为数据库设计注意事项提供有价值的输入,例如如何最好地对投影进行分段和排序,或促进在群集中更好地分布数据处理。
例如,分析可能会显示数据倾斜,其中某些节点处理的数据比其他节点多。系统表 执行_引擎_配置文件 中的 rows produced
计数器显示每个运算符所处理的行数。比较给定运算符跨所有节点的 rows produced
可以揭示是否存在数据倾斜问题。
此部分中的主题重点介绍如何通过 vsql 语句获取配置文件数据。您还可以在管理控制台中查看分析数据。
1 - 启用分析
可以在以下三个范围内启用分析:
Vertica 元函数
SHOW_PROFILING_CONFIG
显示是否在全局范围和会话范围内启用分析。在以下示例中,该函数显示在当前会话的所有类别中禁用了分析,并在所有类别中全局启用了分析:
=> SELECT SHOW_PROFILING_CONFIG();
SHOW_PROFILING_CONFIG ------------------------------------------
Session Profiling: Session off, Global on
EE Profiling: Session off, Global on
Query Profiling: Session off, Global on
(1 row)
全局分析
当为给定类别启用或禁用全局分析时,该设置将在所有数据库会话中保留。可以使用
ALTER DATABASE
设置全局分析,如下所示:
ALTER DATABASE db-spec SET profiling-category = {0 | 1}
profiling-category 使用以下实参之一指定分析类别:
例如,以下语句对当前 (DEFAULT
) 数据库全局启用查询分析:
=> ALTER DATABASE DEFAULT SET GlobalQueryProfiling = 1;
会话分析
可以为当前会话启用会话分析,并一直持续到您显式禁用分析或会话结束。可以使用以下 Vertica 元函数设置会话分析:
profiling-type 使用以下实参之一指定要启用或禁用的分析数据的类型:
例如,以下语句为每个查询的执行运行启用会话范围分析:
=> SELECT ENABLE_PROFILING('ee');
ENABLE_PROFILING
----------------------
EE Profiling Enabled
(1 row)
语句分析
可以通过在单个 SQL 语句前面加上关键字
PROFILE
,来启用对这些语句的分析。可以分析 SELECT
语句或任何 DML 语句(例如
INSERT
、
UPDATE
、
COPY
和
MERGE
)。有关详细信息,请参阅分析单个语句。
分析范围的优先级
Vertica 按优先级降序在以下范围内检查会话和查询分析:
-
语句分析(最高)
-
会话分析(如果启用了全局分析,则忽略)
-
全局分析(最低)
无论查询和会话分析设置如何,Vertica 始终在相关系统表中保存最少量的分析数据:QUERY_PROFILES
、QUERY_PLAN_PROFILES
和 SESSION_PROFILES
。
对于执行引擎分析,Vertica 首先检查配置参数 SaveDCEEProfileThresholdUS
的设置。如果查询运行时间超过指定阈值(默认为 60 秒),Vertica 会收集该查询的执行引擎数据,并将其保存到系统表
QUERY_CONSUMPTION
和
执行_引擎_配置文件
中。仅当查询的持续时间低于阈值时,Vertica 才使用其他范围(语句、会话、全局)的分析设置。
2 - 分析单个语句
要分析单个语句,请在其前面加上
PROFILE
前缀。可以分析查询 (SELECT
) 语句或任何 DML 语句,例如
INSERT
、
UPDATE
、
COPY
和
MERGE
。语句返回分析摘要:
例如:
=> PROFILE SELECT customer_name, annual_income FROM public.customer_dimension
WHERE (customer_gender, annual_income) IN (SELECT customer_gender, MAX(annual_income)
FROM public.customer_dimension GROUP BY customer_gender);NOTICE 4788: Statement is being profiled
HINT: Select * from v_monitor.execution_engine_profiles where transaction_id=45035996274760535 and statement_id=1;
NOTICE 3557: Initiator memory for query: [on pool general: 2783428 KB, minimum: 2312914 KB]
NOTICE 5077: Total memory required by query: [2783428 KB]
customer_name | annual_income
------------------+---------------
James M. McNulty | 999979
Emily G. Vogel | 999998
(2 rows)
可以使用分析标识符 transaction_id
和 statement_id
从系统表
执行_引擎_配置文件
和
QUERY_PLAN_PROFILES
中获取此查询的详细分析信息。还可以使用这些标识符从系统表
QUERY_CONSUMPTION
中获取资源消耗数据。
例如:
=> SELECT path_id, path_line::VARCHAR(68), running_time FROM v_monitor.query_plan_profiles
WHERE transaction_id=45035996274760535 AND statement_id=1 ORDER BY path_id, path_line_index;
path_id | path_line | running_time
---------+----------------------------------------------------------------------+-----------------
1 | +-JOIN HASH [Semi] [Cost: 631, Rows: 25K (NO STATISTICS)] (PATH ID: | 00:00:00.052478
1 | | Join Cond: (customer_dimension.customer_gender = VAL(2)) AND (cus |
1 | | Materialize at Output: customer_dimension.customer_name |
1 | | Execute on: All Nodes |
2 | | +-- Outer -> STORAGE ACCESS for customer_dimension [Cost: 30, Rows | 00:00:00.051598
2 | | | Projection: public.customer_dimension_b0 |
2 | | | Materialize: customer_dimension.customer_gender, customer_d |
2 | | | Execute on: All Nodes |
2 | | | Runtime Filters: (SIP1(HashJoin): customer_dimension.custom |
4 | | | +---> GROUPBY HASH (GLOBAL RESEGMENT GROUPS) (LOCAL RESEGMENT GR | 00:00:00.050566
4 | | | | Aggregates: max(customer_dimension.annual_income) |
4 | | | | Group By: customer_dimension.customer_gender |
4 | | | | Execute on: All Nodes |
5 | | | | +---> STORAGE ACCESS for customer_dimension [Cost: 30, Rows: 5 | 00:00:00.09234
5 | | | | | Projection: public.customer_dimension_b0 |
5 | | | | | Materialize: customer_dimension.customer_gender, custom |
5 | | | | | Execute on: All Nodes |
(17 rows)
3 - 标记语句
要快速识别查询和其他操作以进行分析和调试,请包含 LABEL 提示。
LABEL 提示在以下语句中有效:
例如:
SELECT /*+label(myselectquery)*/ COUNT(*) FROM t;
INSERT /*+label(myinsertquery)*/ INTO t VALUES(1);
向一个或多个语句添加标签后,查询 QUERY_PROFILES 系统表,以查看哪些查询是使用您提供的标签运行的。QUERY_PROFILES 系统表 IDENTIFIER 列返回您之前分配给语句的用户定义标签。您还可以获取其他特定于查询的数据,这些数据可用于查询其他系统表,例如事务 ID。
例如:
=> SELECT identifier, query FROM query_profiles;
identifier | query
---------------+-----------------------------------------------------------
myselectquery | SELECT /*+label(myselectquery)*/ COUNT(*) FROM t;
myinsertquery | INSERT /*+label(myinsertquery)*/ INTO t VALUES(1);
myupdatequery | UPDATE /*+label(myupdatequery)*/ t SET a = 2 WHERE a = 1;
mydeletequery | DELETE /*+label(mydeletequery)*/ FROM t WHERE a = 1;
| SELECT identifier, query from query_profiles;
(5 rows)
4 - 实时分析
可以通过查询系统表
执行_引擎_配置文件
来监控长时间运行的查询的执行。此表包含可用于内部操作和用户语句的分析计数器。可以使用 Linux watch
命令频繁地查询此表。
对实时分析数据的查询需要事务 ID。如果事务执行多个语句,则查询还需要语句 ID 来标识所需的语句。如果分析单个查询,则查询会返回语句的事务和语句 ID。还可以从
SYSTEM_SESSIONS
系统表中获取事务和语句 ID。
分析计数器
执行_引擎_配置文件
系统表包含可用于内部操作和用户语句的分析计数器。实时分析计数器可用于所有语句的执行,包括
合并、
恢复和
刷新等内部操作。除非在特定 SQL 语句中使用 PROFILE
关键字显式地启用分析,或者普遍地为数据库和/或当前会话启用分析,否则在语句完成后分析计数器将不可用。
有用的计数器包括:
-
执行时间 (µs)
-
生成的行数
-
合并阶段总数
-
已完成的合并阶段数
-
当前临时文件大小(字节数)
可以通过查询
执行_引擎_配置文件
来查看所有可用的计数器:
=> SELECT DISTINCT(counter_name) FROM EXECUTION_ENGINE_PROFILES;
若要监控分析计数器,可使用检索到的事务 ID (a000000000027
) 运行类似如下所示的命令:
=> SELECT * FROM execution_engine_profiles
WHERE TO_HEX(transaction_id)='a000000000027'
AND counter_name = 'execution time (us)'
ORDER BY node_name, counter_value DESC;
以下示例将查找每个节点上执行时间最长的运算符:
=> SELECT node_name, operator_name, counter_value execution_time_us FROM V_MONITOR.EXECUTION_ENGINE_PROFILES WHERE counter_name='execution time (us)' LIMIT 1 OVER(PARTITION BY node_name ORDER BY counter_value DESC);
node_name | operator_name | execution_time_us
------------------+---------------+-------------------
v_vmart_node0001 | Join | 131906
v_vmart_node0002 | Join | 227778
v_vmart_node0003 | NetworkSend | 524080
(3 rows)
Linux watch 命令
可以使用 Linux watch
命令经常地监控长时间运行的查询。常见使用案例包括:
在以下示例中,watch
将查询每个节点上执行时间最长的运算符。该命令指定每秒重新执行一次查询:
watch -n 1 -d "vsql VMart -c\"SELECT node_name, operator_name, counter_value execution_time_us
FROM v_monitor.execution_engine_profiles WHERE counter_name='execution time (us)'
LIMIT 1 OVER(PARTITION BY node_name ORDER BY counter_value DESC);
Every 1.0s: vsql VMart -c"SELECT node_name, operator_name, counter_value execution_time_us FROM v_monitor.execu... Thu Jan 21 15:00:44 2016
node_name | operator_name | execution_time_us
------------------+---------------+-------------------
v_vmart_node0001 | Root | 110266
v_vmart_node0002 | UnionAll | 38932
v_vmart_node0003 | Scan | 22058
(3 rows)
5 - 分析查询资源消耗
Vertica 收集所有查询(包括那些失败的查询)的资源使用情况数据,并将这些数据汇总到系统表
QUERY_CONSUMPTION
中。这些数据包括有关每个查询的以下信息:
-
时钟持续时间
-
消耗的 CPU 周期
-
保留和分配的内存
-
发送和接收的网络字节数
-
读取和写入的磁盘字节数
-
溢出的字节数
-
分配的线程数
-
输出到客户端的行数
-
读取和写入的行数
可以通过查询的事务和语句 ID 获取有关各查询的信息。TRANSACTION_ID
和 STATEMENT_ID
列为每个查询语句提供唯一的键。
注意
有一个例外:具有多个计划的查询每个计划一条记录。
例如,会分析以下查询:
=> PROFILE SELECT pd.category_description AS 'Category', SUM(sf.sales_quantity*sf.sales_dollar_amount) AS 'Total Sales'
FROM store.store_sales_fact sf
JOIN public.product_dimension pd ON pd.product_version=sf.product_version AND pd.product_key=sf.product_key
GROUP BY pd.category_description;
NOTICE 4788: Statement is being profiled
HINT: Select * from v_monitor.execution_engine_profiles where transaction_id=45035996274751822 and statement_id=1;
NOTICE 3557: Initiator memory for query: [on pool general: 256160 KB, minimum: 256160 KB]
NOTICE 5077: Total memory required by query: [256160 KB]
Category | Total Sales
----------------------------------+-------------
Non-food | 1147919813
Misc | 1158328131
Medical | 1155853990
Food | 4038220327
(4 rows)
可以使用 Vertica 返回的事务和语句 ID 从 QUERY_CONSUMPTION
获取分析数据,例如,通过网络为给定查询发送的总字节数:
=> SELECT NETWORK_BYTES_SENT FROM query_consumption WHERE transaction_id=45035996274751822 AND statement_id=1;
NETWORK_BYTES_SENT
--------------------
757745
(1 row)
注意
QUERY_CONSUMPTION
保存来自所有查询的数据,无论是否显式分析。
QUERY_CONSUMPTION 与 EXECUTION _ENGINE_PROFILES
QUERY_CONSUMPTION
包括它从
执行_引擎_配置文件
中的计数器汇总的数据。在前面的示例中,NETWORK_BYTES_SENT
汇总了可通过 EXECUTION_ENGINE_PROFILES
中的多个计数器访问的数据。EXECUTION_ENGINE_PROFILES
的等效查询如下所示:
=> SELECT operator_name, counter_name, counter_tag, SUM(counter_value) FROM execution_engine_profiles
WHERE transaction_id=45035996274751822 AND statement_id=1 AND counter_name='bytes sent'
GROUP BY ROLLUP (operator_name, counter_name, counter_tag) ORDER BY 1,2,3, GROUPING_ID();
operator_name | counter_name | counter_tag | SUM
---------------+--------------+--------------------------------+--------
NetworkSend | bytes sent | Net id 1000 - v_vmart_node0001 | 252471
NetworkSend | bytes sent | Net id 1000 - v_vmart_node0002 | 251076
NetworkSend | bytes sent | Net id 1000 - v_vmart_node0003 | 253717
NetworkSend | bytes sent | Net id 1001 - v_vmart_node0001 | 192
NetworkSend | bytes sent | Net id 1001 - v_vmart_node0002 | 192
NetworkSend | bytes sent | Net id 1001 - v_vmart_node0003 | 0
NetworkSend | bytes sent | Net id 1002 - v_vmart_node0001 | 97
NetworkSend | bytes sent | | 757745
NetworkSend | | | 757745
| | | 757745
(10 rows)
QUERY_CONSUMPTION
和 EXECUTION_ENGINE_PROFILES
也有如下不同:
6 - 分析查询计划
要通过查询计划及其各个
路径监控实时数据流,请查询以下系统表:
执行_引擎_配置文件
和
QUERY_PLAN_PROFILES
。这些表提供了有关 Vertica 如何执行查询计划及其各个
路径的数据:
每个查询计划路径都具有唯一的 ID,如以下
EXPLAIN
输出片段中所示。
每个表都提供特定于路径的数据。例如,QUERY_PLAN_PROFILES
为每个路径提供高级别数据,包括:
-
查询操作执行时长
-
路径操作所用的内存大小
-
通过网络发送/接收的数据大小
例如,您可能观察到 GROUP BY HASH
操作的执行时间为 0.2 秒,使用的内存为 100MB。
要求
实时分析至少需要待监控事务的 ID。如果事务包括多个语句,则还需要语句 ID。可以通过对要分析的查询发出
PROFILE
来获取语句和事务 ID。随后可使用这些标识符来查询系统表 EXECUTION_ENGINE_PROFILES
和 QUERY_PLAN_PROFILES
。
有关详细信息,请参阅分析单个语句。
6.1 - 获取小型查询的查询计划状态
存储在
执行_引擎_配置文件
系统表中的实时分析计数器可用于当前执行的所有语句,包括
合并等内部操作。
如果满足以下任一条件,则可以在查询执行完成后使用分析计数器:
分析计数器保存在 EXECUTION_ENGINE_PROFILES
系统表中,直至超出存储配额。
例如:
-
分析查询以从 EXECUTION_ENGINE_PROFILES
获取 transaction_id
和 statement_id
。例如:
=> PROFILE SELECT * FROM t1 JOIN t2 ON t1.x = t2.y;
NOTICE 4788: Statement is being profiled
HINT: Select * from v_monitor.execution_engine_profiles where transaction_id=45035996273955065 and statement_id=4;
NOTICE 3557: Initiator memory for query: [on pool general: 248544 KB, minimum: 248544 KB]
NOTICE 5077: Total memory required by query: [248544 KB]
x | y | z
---+---+-------
3 | 3 | three
(1 row)
-
查询系统表
QUERY_PLAN_PROFILES
。
注意
为了获得最佳结果,请按列 transaction_id
、statement_id
、path_id
和 path_line_index
进行排序。
=> SELECT ... FROM query_plan_profiles
WHERE transaction_id=45035996273955065 and statement_id=4;
ORDER BY transaction_id, statement_id, path_id, path_line_index;
6.2 - 获取大型查询的查询计划状态
实时分析用于监控大型(长时间运行的)查询。请按照以下步骤监控大型查询的计划:
-
通过查询系统表
CURRENT_SESSION
获取要分析的查询计划的语句和事务 ID:
=> SELECT transaction_id, statement_id from current_session;
transaction_id | statement_id
-------------------+--------------
45035996273955001 | 4
(1 row)
-
运行查询:
=> SELECT * FROM t1 JOIN t2 ON x=y JOIN ext on y=z;
-
查询系统表
QUERY_PLAN_PROFILES
,并对 transaction_id、statement_id、path_id 和 path_line_index 列进行排序。
=> SELECT ... FROM query_plan_profiles WHERE transaction_id=45035996273955001 and statement_id=4
ORDER BY transaction_id, statement_id, path_id, path_line_index;
也可以使用 Linux watch
命令监控长时间运行的查询(请参阅实时分析)。
示例
以下一系列命令会为长时间运行的查询创建表,然后查询系统表 QUERY_PLAN_PROFILES
:
-
创建名为 longq
的表:
=> CREATE TABLE longq(x int);
CREATE TABLE
=> COPY longq FROM STDIN;
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> 1
>> 2
>> 3
>> 4
>> 5
>> 6
>> 7
>> 8
>> 9
>> 10
>> \.
=> INSERT INTO longq SELECT f1.x+f2.x+f3.x+f4.x+f5.x+f6.x+f7.x
FROM longq f1
CROSS JOIN longq f2
CROSS JOIN longq f3
CROSS JOIN longq f4
CROSS JOIN longq f5
CROSS JOIN longq f6
CROSS JOIN longq f7;
OUTPUT
----------
10000000
(1 row)
=> COMMIT;
COMMIT
-
通过使用 vsql \o
命令禁止查询在终端窗口上输出:
=> \o /home/dbadmin/longQprof
-
查询新表:
=> SELECT * FROM longq;
-
获取事务和语句 ID:
=> SELECT transaction_id, statement_id from current_session;
transaction_id | statement_id
-------------------+--------------
45035996273955021 | 4
(1 row)
-
关闭 \o
命令以便 Vertica 继续将查询计划信息保存到您已指定的文件。或者,使其保持打开状态并在查询系统表 QUERY_PLAN_PROFILES
后检查该文件。
=> \o
-
查询系统表 QUERY_PLAN_PROFILES
:
=> SELECT
transaction_id,
statement_id,
path_id,
path_line_index,
is_executing,
running_time,
path_line
FROM query_plan_profiles
WHERE transaction_id=45035996273955021 AND statement_id=4
ORDER BY transaction_id, statement_id, path_id, path_line_index;
6.3 - 改善 QUERY_PLAN_PROFILES 输出的可读性
QUERY_PLAN_PROFILES
表的输出会因 path_line
列而非常宽。为提高可读性,使用下面的一个或多个选项查询 QUERY_PLAN_PROFILES
:
-
按 transaction_id
、statement_id
、path_id
和 path_line_index
对输出排序:
=> SELECT ... FROM query_plan_profiles
WHERE ...
ORDER BY transaction_id, statement_id, path_id, path_line_index;
-
使用列别名减小列宽:
=> SELECT statement_id AS sid, path_id AS id, path_line_index AS order,
is_started AS start, is_completed AS end, is_executing AS exe,
running_time AS run, memory_allocated_bytes AS mem,
read_from_disk_bytes AS read, received_bytes AS rec,
sent_bytes AS sent, FROM query_plan_profiles
WHERE transaction_id=45035996273910558 AND statement_id=3
ORDER BY transaction_id, statement_id, path_id, path_line_index;
-
使用 vsql \o
命令将
EXPLAIN
输出重定向至文件:
=> \o /home/dbadmin/long-queries
=> EXPLAIN SELECT * FROM customer_dimension;
=> \o
6.4 - 管理查询分析数据
Vertica 会一直保留查询数据,直至超出表的存储配额,此时它会自动清除最旧的查询,以便为新查询腾出空间。还可以通过调用以下函数之一来清除已分析的数据:
配置数据保留策略
Vertica 按照配置的保留策略的规定保留它收集的历史数据。
6.5 - 分析次优查询计划
如果分析未涵盖不理想的查询,调用下列函数之一可能有所帮助:
您还可以通过 Database Designer 运行查询。请参阅增量设计。
7 - 计数器信息的示例视图
EXECUTION_ENGINE_PROFILES 表包含每个分析计数器的数据作为表中的一行。例如,执行时间 (us) 计数器在一个行中,该行生成的计数器在另一行中。由于有许多不同的分析计数器,因此每个运算符存在多行分析数据。系统默认安装一些示例视图,以简化查看分析计数器的过程。
运行脚本以创建示例视图
以下脚本将创建 v_demo
架构并将视图置于该架构中。
/opt/vertica/scripts/demo_eeprof_view.sql
使用示例视图查看计数器值
每个分析计数器都有一个视图,用于简化查看单个计数器值的过程。例如,若要查看所有运算符的执行时间,请从数据库发出以下命令:
=> SELECT * FROM v_demo.eeprof_execution_time_us;
要查看可用于所有分析查询的所有计数器值:
=> SELECT * FROM v_demo.eeprof_counters;
要选择可用于所有分析查询的所有不同运算符:
=> SELECT * FROM v_demo.eeprof_operators;
合并示例视图
以下视图可以合并:
=> SELECT * FROM v_demo.eeprof_execution_time_us
NATURAL LEFT OUTER JOIN v_demo.eeprof_rows_produced;
要查看执行时间和为特定事务生成的行以及按每个节点执行时间所排列的 statement_id
:
=> SELECT * FROM v_demo.eeprof_execution_time_us_rank
WHERE transaction_id=45035996273709699
AND statement_id=1
ORDER BY transaction_id, statement_id, node_name, rk;
要查看按每个节点执行时间所排列的前五个运算符:
=> SELECT * FROM v_demo.eeprof_execution_time_us_rank
WHERE transaction_id=45035996273709699
AND statement_id=1 AND rk<=5
ORDER BY transaction_id, statement_id, node_name, rk;