慢Query日志查看與分析
當(dāng)Hologres實(shí)例出現(xiàn)響應(yīng)或查詢速度變慢時(shí),您可以查看與分析慢Query日志快速定位問題所在。慢Query的查看與分析可以幫助您對(duì)系統(tǒng)中發(fā)生的慢Query或失敗Query進(jìn)行識(shí)別、診斷和分析,并進(jìn)一步采取優(yōu)化措施,以提高系統(tǒng)整體性能。本文為您介紹在Hologres中如何查看慢Query日志并分析。
版本說明
Hologres版本號(hào) | 功能 | 說明 |
V0.10 | 新增慢Query日志查看與分析功能。 |
|
V2.2.7 | 優(yōu)化log_min_duration_statement參數(shù)默認(rèn)值 | 慢Query日志記錄所有的DDL語句、所有執(zhí)行失敗的SQL語句以及執(zhí)行時(shí)間大于 從Hologres V2.2.7版本開始,將 |
使用限制
在Hologres中查詢慢Query日志,具體限制如下:
慢Query日志默認(rèn)保留一個(gè)月的數(shù)據(jù),但是HoloWeb僅支持查最近7天的數(shù)據(jù),如果需要查詢一個(gè)月內(nèi)的數(shù)據(jù)請(qǐng)使用SQL進(jìn)行查詢。
為了保證系統(tǒng)穩(wěn)定性,避免流量超載,單次查詢最多返回10000條慢Query日志。慢Query日志中的部分字段有長(zhǎng)度限制,詳情請(qǐng)參見
query_log
表字段說明。慢Query日志屬于Hologres的元倉系統(tǒng),慢Query日志查詢失敗不會(huì)影響實(shí)例中的業(yè)務(wù)Query運(yùn)行,故慢Query日志的穩(wěn)定性不在產(chǎn)品的SLA保護(hù)范圍內(nèi)。
查看query_log表
Hologres的慢Query查詢?nèi)罩敬鎯?chǔ)于hologres.hg_query_log系統(tǒng)表中,其中:
在實(shí)例升級(jí)至V0.10版本后,將會(huì)默認(rèn)采集執(zhí)行時(shí)間大于100 ms的慢DML Query以及所有的DDL操作。
自V3.0.2版本開始,支持在原有的hologres.hg_query_log中,使用聚合方式記錄執(zhí)行時(shí)間小于100 ms的DML和查詢的記錄。
系統(tǒng)會(huì)將執(zhí)行時(shí)間小于100 ms,成功且有指紋的Query(DQL和DML)操作進(jìn)行聚合記錄。
聚合的主要列為:server_addr、usename、datname、warehouse_id、application_name、digest。
每個(gè)連接每分鐘會(huì)匯總一次后上報(bào)。
hologres.hg_query_log系統(tǒng)表,包含的字段信息介紹如下。
字段 | 字段類型 | 100 ms以上DML和DQL明細(xì)記錄含義說明 | 100 ms以下DML和DQL聚合記錄含義說明 |
usename | text | 查詢的用戶名。 | 查詢的用戶名。 |
status | text | 查詢的最終狀態(tài),成功或失敗。
| 查詢的最終狀態(tài),成功(SUCCESS),聚合數(shù)據(jù)僅記錄成功的記錄。 |
query_id | text | Query的ID,代表Query的唯一性。 失敗的Query一定會(huì)有query_id,成功的Query不一定會(huì)有。 | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的Query ID。 |
digest | text | SQL指紋編碼。 對(duì)于SELECT、INSERT、DELETE、UPDATE類型的Query,系統(tǒng)會(huì)計(jì)算一個(gè)MD5哈希值作為該Query的SQL指紋。SQL指紋采集和計(jì)算規(guī)則詳情,請(qǐng)參見SQL指紋。 說明 從Hologres V2.2版本開始,新增digest列以展示SQL指紋編碼。若您的實(shí)例為V2.1或以下版本,可聯(lián)系Hologres技術(shù)支持升級(jí)實(shí)例。 | SQL指紋編碼。 |
datname | text | 查詢的數(shù)據(jù)庫名稱。 | 查詢的數(shù)據(jù)庫名稱。 |
command_tag | text | 查詢的類型。 包括:
| 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的查詢的類型。 |
duration | integer | 查詢的耗時(shí)(ms)。
系統(tǒng)默認(rèn)只展示大于1s的DML和所有DDL,可以通過GUC參數(shù) | 聚合周期內(nèi),同聚合主鍵所有Query的查詢耗時(shí)的平均值。 |
message | text | 報(bào)錯(cuò)的信息。 | 空。 |
query_start | timestamptz | 查詢開始時(shí)間。 | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的查詢開始時(shí)間。 |
query_date | text | 查詢開始日期。 | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的查詢開始日期。 |
query | text | 查詢的文本內(nèi)容。 Query的長(zhǎng)度上限是51200個(gè)字符,超過可能會(huì)被截?cái)唷?/p> | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的查詢的文本內(nèi)容。 |
result_rows | bigint | 返回的行數(shù)。 如果是INSERT命令,則返回插入的行數(shù)。 | 聚合周期內(nèi),同聚合主鍵所有Query的result_rows的平均值。 |
result_bytes | bigint | 返回的字節(jié)數(shù)。 | 聚合周期內(nèi),同聚合主鍵所有Query的result_bytes的平均值。 |
read_rows | bigint | 讀取的數(shù)據(jù)行數(shù)。 非精確值。如果使用了Bitmap索引,跟實(shí)際的掃描行數(shù)有差別。 | 聚合周期內(nèi),同聚合主鍵所有Query的read_rows的平均值。 |
read_bytes | bigint | 讀取的字節(jié)數(shù)。 | 聚合周期內(nèi),同聚合主鍵所有Query的read_bytes的平均值。 |
affected_rows | bigint | DML影響的行數(shù)。 | 聚合周期內(nèi),同聚合主鍵所有Query的affected_rows的平均值。 |
affected_bytes | bigint | DML影響的字節(jié)數(shù)。 | 聚合周期內(nèi),同聚合主鍵所有Query的affected_bytes的平均值。 |
memory_bytes | bigint | 各節(jié)點(diǎn)上使用的內(nèi)存峰值的累加值(非精確)。 代表Query在所有運(yùn)行節(jié)點(diǎn)上使用的內(nèi)存峰值的累加值。粗略地體現(xiàn)Query的數(shù)據(jù)讀取量。 | 聚合周期內(nèi),同聚合主鍵所有Query的memory_bytes的平均值。 |
shuffle_bytes | bigint | 數(shù)據(jù)Shuffle估計(jì)字節(jié)數(shù)(非精確)。 粗略地體現(xiàn)數(shù)據(jù)在網(wǎng)絡(luò)中的傳輸量。 | 聚合周期內(nèi),同聚合主鍵所有Query的shuffle_bytes的平均值。 |
cpu_time_ms | bigint | 總的CPU時(shí)間,單位:毫秒(ms),非精確。 體現(xiàn)所有計(jì)算任務(wù)所耗費(fèi)的CPU時(shí)間,是多個(gè)CPU Core計(jì)算時(shí)間的累加,粗略地體現(xiàn)復(fù)雜度。 | 聚合周期內(nèi),同聚合主鍵所有Query的cpu_time_ms的平均值 |
physical_reads | bigint | 物理讀的次數(shù)。 反映從磁盤讀取Record Batch的次數(shù),粗略地體現(xiàn)內(nèi)存緩存未命中數(shù)量。 | 聚合周期內(nèi),同聚合主鍵所有Query的physical_reads的平均值。 |
pid | integer | 查詢服務(wù)進(jìn)程ID。 | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的查詢服務(wù)進(jìn)程ID。 |
application_name | text | 查詢應(yīng)用類型。 其中常見的應(yīng)用類型如下:
其余應(yīng)用建議業(yè)務(wù)上在連接Hologres時(shí),連接串上顯式指定 | 查詢應(yīng)用類型。 |
engine_type | text[] | 查詢用到的引擎。 包含如下引擎類型:
| 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的查詢用到的引擎。 |
client_addr | text | Query的來源地址。 代表應(yīng)用的出口IP,不一定是真實(shí)的應(yīng)用IP。 | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的Query的來源地址。 |
table_write | text | SQL寫入的表。 | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的SQL寫入的表。 |
table_read | text[] | SQL讀取的表。 | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的SQL讀取的表。 |
session_id | text | Session ID。 | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的Session ID。 |
session_start | timestamptz | Session開啟時(shí)間。 代表連接開始建立的時(shí)間。 | 聚合周期內(nèi),同聚合主鍵所有Query的Session開啟時(shí)間。 |
command_id | text | 命令或語句編號(hào)ID。 | 聚合周期內(nèi),同聚合主鍵所有Query的命令或語句編號(hào)ID。 |
optimization_cost | integer | 查詢執(zhí)行計(jì)劃的耗時(shí)。 耗時(shí)較高通常情況是SQL較復(fù)雜。 | 聚合周期內(nèi),同聚合主鍵所有Query的查詢執(zhí)行計(jì)劃的耗時(shí)。 |
start_query_cost | integer | 查詢啟動(dòng)耗時(shí)。 耗時(shí)較高通常是因?yàn)樵诘孺i或者等待資源。 | 聚合周期內(nèi),同聚合主鍵所有Query的查詢啟動(dòng)耗時(shí)。 |
get_next_cost | integer | 查詢執(zhí)行耗時(shí)。 耗時(shí)較高通常是因?yàn)橛?jì)算量太大,執(zhí)行時(shí)間較長(zhǎng),可根據(jù)業(yè)務(wù)情況優(yōu)化SQL。 | 聚合周期內(nèi),同聚合主鍵所有Query的查詢執(zhí)行耗時(shí)。 |
extended_cost | text | 查詢的其他詳細(xì)耗時(shí)。 除optimization_cost 、start_query_cost 、get_next_cost三個(gè)耗時(shí)之外的其他耗時(shí),可以通過
| 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的其他詳細(xì)耗時(shí)。 |
plan | text | 查詢對(duì)應(yīng)的執(zhí)行計(jì)劃。 執(zhí)行計(jì)劃長(zhǎng)度上限是102400個(gè)字符,超過可能會(huì)被截?cái)啵梢酝ㄟ^GUC參數(shù) | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的查詢對(duì)應(yīng)的執(zhí)行計(jì)劃。 |
statistics | text | 查詢對(duì)應(yīng)的執(zhí)行統(tǒng)計(jì)信息。 統(tǒng)計(jì)信息長(zhǎng)度上限是102400個(gè)字符,超過可能會(huì)被截?cái)啵梢酝ㄟ^GUC參數(shù) | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的查詢對(duì)應(yīng)的執(zhí)行統(tǒng)計(jì)信息。 |
visualization_info | text | 查詢Plan可視化信息。 | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的查詢Plan可視化信息。 |
query_detail | text | 查詢的其他擴(kuò)展信息(JSON格式存儲(chǔ))。 說明 擴(kuò)展信息長(zhǎng)度上限是10240個(gè)字符,超過可能會(huì)被截?cái)唷?/p> | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的查詢的其他擴(kuò)展信息。 |
query_extinfo | text[] |
說明 本地賬號(hào)登錄、SLR登錄、STS登錄不會(huì)記錄AccessKey ID。若使用臨時(shí)賬號(hào)登錄,僅記錄臨時(shí)AccessKey ID。 | 聚合周期內(nèi),同聚合主鍵第一個(gè)Query的其他擴(kuò)展信息。 |
calls | INT | 因?yàn)槊骷?xì)記錄無聚合行為,所以為1。 | 表示在聚合周期內(nèi),相同聚合主鍵的查詢數(shù)量。 |
agg_stats | JSONB | 空。 | 記錄在聚合周期內(nèi),相同聚合主鍵的查詢的duration、memory_bytes、cpu_time_ms、physical_reads、optimization_cost、start_query_cost、get_next_cost等數(shù)值字段的MIN、MAX、AVG等統(tǒng)計(jì)值。 |
extended_info | JSONB | 其他擴(kuò)展信息。記錄Query Queue、Serverless Computing等擴(kuò)展信息。
| 空。 |
calls、agg_stats字段為V3.0.2版本新增字段。
授予查看權(quán)限
慢Query日志需要有一定的權(quán)限才能查看,其權(quán)限規(guī)則和授權(quán)方式說明如下:
查看實(shí)例所有DB的慢Query日志。
授予用戶Superuser權(quán)限。
Superuser賬號(hào)可以查看實(shí)例所有DB的全部慢Query日志,給用戶授予Superuser用戶的權(quán)限,使用戶有權(quán)限查看實(shí)例所有DB的慢Query日志。
ALTER USER "云賬號(hào)ID" SUPERUSER;--將“云賬號(hào)ID”替換為實(shí)際用戶名。如果是RAM用戶,賬號(hào)ID前需要添加“p4_”。
將用戶添加到pg_read_all_stats用戶組。
除Superuser外,Hologres還支持pg_read_all_stats用戶組查看所有DB慢Query日志,普通用戶如果需要查看所有日志,可以聯(lián)系Superuser授權(quán)加入該用戶組。授權(quán)方式如下:
GRANT pg_read_all_stats TO "云賬號(hào)ID";--專家權(quán)限模型授權(quán) CALL spm_grant('pg_read_all_stats', '云賬號(hào)ID'); -- SPM權(quán)限模型 CALL slpm_grant('pg_read_all_stats', '云賬號(hào)ID'); -- SLPM權(quán)限模型
查看本DB的慢Query日志。
開啟簡(jiǎn)單權(quán)限模型(SPM)或基于Schema級(jí)別的簡(jiǎn)單權(quán)限模型(SLPM),將用戶加入db_admin用戶組,db_admin角色可以查看本DB的query日志。
CALL spm_grant('<db_name>_admin', '云賬號(hào)ID'); -- SPM權(quán)限模型 CALL slpm_grant('<db_name>.admin', '云賬號(hào)ID'); -- SLPM權(quán)限模型
普通用戶只能查詢當(dāng)前賬號(hào)對(duì)應(yīng)DB下自己執(zhí)行的慢Query日志。
HoloWeb可視化查看慢Query
您可以通過HoloWeb可視化查看慢Query日志。
當(dāng)前HoloWeb支持查看最多七天的歷史慢Query日志。
僅支持Superuser賬號(hào)查看,普通有權(quán)限的賬號(hào)請(qǐng)使用SQL命令查看。
登錄HoloWeb控制臺(tái),詳情請(qǐng)參見連接HoloWeb并執(zhí)行查詢。
單擊頂部導(dǎo)航欄的診斷與優(yōu)化。
在左側(cè)導(dǎo)航欄單擊歷史慢Query。
在歷史慢Query頁面頂部,編輯查詢條件。
參數(shù)說明請(qǐng)參見歷史慢Query。
單擊查詢,在Query趨勢(shì)分析和Query列表區(qū)域展示查詢結(jié)果。
Query趨勢(shì)分析
Query趨勢(shì)分析通過可視化的方式展示近期慢Query、失敗Query發(fā)生的趨勢(shì),可以重點(diǎn)監(jiān)控慢Query發(fā)生頻率較高的階段,更好的定位問題高發(fā)期并集中解決問題。
Query列表
Query列表可視化展示慢Query、失敗Query的詳細(xì)信息,參數(shù)說明請(qǐng)參見歷史慢Query。也可以單擊自定義列選擇Query列表需要展示的列信息。
SQL指紋
自Hologres V2.2版本起,存放慢Query查詢?nèi)罩镜南到y(tǒng)表hologres.hg_query_log中,新增digest列以展示SQL指紋。對(duì)于SELECT/INSERT/DELETE/UPDATE類型的Query,系統(tǒng)會(huì)計(jì)算一個(gè)MD5哈希值作為該Query的SQL指紋,以幫助業(yè)務(wù)進(jìn)一步Query歸類分析。
SQL指紋的采集和計(jì)算規(guī)則如下:
默認(rèn)僅采集SELECT、INSERT、DELETE以及UPDATE四種類型Query的指紋。
對(duì)于
INSERT
語句,以常量方式插入表時(shí),SQL指紋不受插入數(shù)據(jù)量的影響。SQL指紋計(jì)算時(shí),對(duì)SQL語句字母大小寫的處理規(guī)則和Hologres在查詢時(shí)SQL語句字母大小寫規(guī)則保持一致。
SQL指紋計(jì)算時(shí),會(huì)忽略查詢中所有空白符(如空格、換行、制表符等)的影響,只考慮SQL語句內(nèi)的結(jié)構(gòu)信息。
SQL指紋計(jì)算時(shí),會(huì)忽略查詢中具體的常數(shù)值對(duì)于指紋的影響。
示例:查詢
SELECT * FROM t WHERE a > 1;
與查詢SELECT * FROM t WHERE a > 2;
所對(duì)應(yīng)的SQL指紋是一致的。對(duì)于Query中的數(shù)組常量,SQL指紋的計(jì)算不受數(shù)組中元素個(gè)數(shù)的影響。
示例:查詢
SELECT * FROM t WHERE a IN (1, 2);
和查詢SELECT * FROM t WHERE a IN (3, 4, 5);
的SQL指紋是相同的。SQL指紋計(jì)算時(shí),會(huì)考慮數(shù)據(jù)庫名稱,并自動(dòng)補(bǔ)全每張表的模式(Schema)屬性,以表名和表的屬性共同區(qū)分不同查詢中的表。
示例:對(duì)于查詢
SELECT * FROM t;
和查詢SELECT * FROM public.t;
而言,只有當(dāng)表t
位于public
模式并且兩個(gè)查詢對(duì)應(yīng)同一張表時(shí),其SQL指紋才相同。
診斷Query
您可以通過查詢hologres.hg_query_log表,獲取慢Query日志。如下將為您介紹進(jìn)行Query日志診斷常用的固定SQL語句。主要包括:
查詢query_log總查詢數(shù)(默認(rèn)為近1個(gè)月內(nèi)的數(shù)據(jù))。
SELECT count(*) FROM hologres.hg_query_log;
執(zhí)行結(jié)果如下,表示近1個(gè)月內(nèi)總共執(zhí)行了44個(gè)耗時(shí)大于指定閾值的Query。
count ------- 44 (1 row)
查詢每個(gè)用戶的慢Query個(gè)數(shù)。
SELECT usename AS "用戶", count(1) as "Query個(gè)數(shù)" FROM hologres.hg_query_log GROUP BY usename order by count(1) desc;
執(zhí)行結(jié)果如下,其中
count(1)
的單位是個(gè)數(shù)。用戶 | Query個(gè)數(shù) -----------------------+----- 1111111111111111 | 27 2222222222222222 | 11 3333333333333333 | 4 4444444444444444 | 2 (4 rows)
查詢某個(gè)慢Query的具體信息。
SELECT * FROM hologres.hg_query_log WHERE query_id = '13001450118416xxxx';
執(zhí)行結(jié)果如下,更多關(guān)于各參數(shù)的說明,請(qǐng)參見查看query_log表。
usename | status | query_id | datname| command_tag | duration | message | query_start | query_date | query | result_rows | result_bytes | read_rows |read_bytes | affected_rows | affected_bytes | memory_bytes | shuffle_bytes | cpu_time_ms | physical_reads | pid | application_name | engine_type | client_addr | table_write | table_read | session_id | session_start | command_id | optimization_cost | start_query_cost | get_next_cost | extended_cost | plan | statistics | visualization_info | query_detail | query_extinfo -----------------------+---------+--------------------+---------+-------------+----------+---------+------------------------+------------+---------------------------------------------------------------------------------------------------------+-------------+--------------+-----------+------------+---------------+----------------+--------------+---------------+-------------+----------------+---------+------------------+-------------+---------------+-------------+------------+-----------------+------------------------+------------+-------------------+------------------+---------------+---------------+------+------------+--------------------+--------------+--------------- p4_11111111111xxxx | SUCCESS | 13001450118416xxxx | dbname | SELECT | 149 | | 2021-03-30 23:45:01+08 | 20210330 | explain analyze SELECT * FROM tablename WHERE user_id = '20210330010xxxx' limit 1000; | 1000 | 417172 | 0 | 0 | -1 | -1 | 26731376 | 476603616 | 321626 | 0 | 1984913 | psql | {HQE} | 33.41.xxx.xxx | | | 6063475a.1e4991 | 2021-03-30 23:44:26+08 | 0 | 58 | 22 | 67 | | | | | | (1 row)
查詢最近某個(gè)時(shí)間段(如10分鐘)消耗比較高的Query。您也可以根據(jù)業(yè)務(wù)需求修改具體時(shí)間,查詢目標(biāo)時(shí)間段消耗比較高的Query。
SELECT status AS "狀態(tài)", duration AS "耗時(shí)(ms)", query_start AS "開始時(shí)間", (read_bytes/1048576)::text || ' MB' AS "讀取量", (memory_bytes/1048576)::text || ' MB' AS "內(nèi)存", (shuffle_bytes/1048576)::text || ' MB' AS "Shuffle", (cpu_time_ms/1000)::text || ' s' AS "CPU時(shí)間", physical_reads as "讀盤", query_id as "QueryID", query::char(30) FROM hologres.hg_query_log WHERE query_start >= now() - interval '10 min' ORDER BY duration DESC, read_bytes DESC, shuffle_bytes DESC, memory_bytes DESC, cpu_time_ms DESC, physical_reads DESC LIMIT 100;
執(zhí)行結(jié)果如下:
狀態(tài) |耗時(shí)(ms) | 開始時(shí)間 | 讀取量 | 內(nèi)存 | Shuffle | CPU時(shí)間 | 讀盤 | QueryID | query ---------+---------+------------------------+--------+-------+---------+---------+------+--------------------+-------------------------------- SUCCESS | 149 | 2021-03-30 23:45:01+08 | 0 MB | 25 MB | 454 MB | 321 s | 0 | 13001450118416xxxx | explain analyze SELECT * FROM SUCCESS | 137 | 2021-03-30 23:49:18+08 | 247 MB | 21 MB | 213 MB | 803 s | 7771 | 13001491818416xxxx | explain analyze SELECT * FROM FAILED | 53 | 2021-03-30 23:48:43+08 | 0 MB | 0 MB | 0 MB | 0 s | 0 | 13001484318416xxxx | SELECT ds::bigint / 0 FROM pub (3 rows)
查看昨日新增的Query數(shù)量。
統(tǒng)計(jì)昨日新增的Query總量。
SELECT COUNT(1) FROM ( SELECT DISTINCT t1.digest FROM hologres.hg_query_log t1 WHERE t1.query_start >= CURRENT_DATE - INTERVAL '1 day' AND t1.query_start < CURRENT_DATE AND NOT EXISTS ( SELECT 1 FROM hologres.hg_query_log t2 WHERE t2.digest = t1.digest AND t2.query_start < CURRENT_DATE - INTERVAL '1 day') AND digest IS NOT NULL ) AS a;
執(zhí)行結(jié)果如下,表示昨日新增Query總量為10個(gè)。
count ------- 10 (1 row)
按照查詢的類型(command_tag)分組統(tǒng)計(jì)昨日新增的Query數(shù)量。
SELECT a.command_tag, COUNT(1) FROM ( SELECT DISTINCT t1.digest, t1.command_tag FROM hologres.hg_query_log t1 WHERE t1.query_start >= CURRENT_DATE - INTERVAL '1 day' AND t1.query_start < CURRENT_DATE AND NOT EXISTS ( SELECT 1 FROM hologres.hg_query_log t2 WHERE t2.digest = t1.digest AND t2.query_start < CURRENT_DATE - INTERVAL '1 day') AND t1.digest IS NOT NULL) AS a GROUP BY 1 ORDER BY 2 DESC;
執(zhí)行結(jié)果如下,表示昨日新增8個(gè)
INSERT
和2個(gè)SELECT
類型的Query。command_tag | count ------------+-------- INSERT | 8 SELECT | 2 (2 rows)
查看昨日新增的Query明細(xì)。
SELECT a.usename, a.status, a.query_id, a.digest, a.datname, a.command_tag, a.query, a.cpu_time_ms, a.memory_bytes FROM ( SELECT DISTINCT t1.usename, t1.status, t1.query_id, t1.digest, t1.datname, t1.command_tag, t1.query, t1.cpu_time_ms, t1.memory_bytes FROM hologres.hg_query_log t1 WHERE t1.query_start >= CURRENT_DATE - INTERVAL '1 day' AND t1.query_start < CURRENT_DATE AND NOT EXISTS ( SELECT 1 FROM hologres.hg_query_log t2 WHERE t2.digest = t1.digest AND t2.query_start < CURRENT_DATE - INTERVAL '1 day' ) AND t1.digest IS NOT NULL ) AS a;
執(zhí)行結(jié)果如下:
usename |status |query_id |digest |datname|command_tag |query |cpu_time_ms |memory_bytes -----------------+--------+--------------------+------------------------------------+-------+-------------+-----------------------------------+--------------+-------------- 111111111111xxxx |SUCCESS |100100425827776xxxx |md58cf93d91c36c6bc9998add971458ba1a |dbname |INSERT |INSERT INTO xxx SELECT * FROM xxx | 1748| 898808596 111111111111xxxx |SUCCESS |100100425827965xxxx |md5f7e87e2c9e0b3d9eddcd6b3bc7f04b3b |dbname |INSERT |INSERT INTO xxx SELECT * FROM xxx | 59891| 6819529886 111111111111xxxx |SUCCESS |100100425829654xxxx |md55612dc09d2d81074fd5deed1aa3eca9b |dbname |INSERT |INSERT INTO xxx SELECT * FROM xxx | 3| 2100039 111111111111xxxx |SUCCESS |100100425829664xxxx |md58d3bf67fbdf2247559bc916586d40011 |dbname |INSERT |INSERT INTO xxx SELECT * FROM xxx | 10729| 2052861937 111111111111xxxx |SUCCESS |100100425830099xxxx |md503bd45d6b2d7701c2617d079b4d55a10 |dbname |INSERT |INSERT INTO xxx SELECT * FROM xxx | 2196| 897948034 111111111111xxxx |SUCCESS |100100425830186xxxx |md5c62169eaf3ea3a0c59bdc834a8141ac4 |dbname |INSERT |INSERT INTO xxx SELECT * FROM xxx | 5268| 1734305972 111111111111xxxx |SUCCESS |100100425830448xxxx |md59aa0c73b24c9c9eba0b34c8fdfc23bb0 |dbname |INSERT |INSERT INTO xxx SELECT * FROM xxx | 2| 2098402 111111111111xxxx |SUCCESS |100100425830459xxxx |md57d22c1d37b68984e9472f11a4c9fd04e |dbname |INSERT |INSERT INTO xxx SELECT * FROM xxx | 113| 76201984 111111111111xxxx |SUCCESS |100100525468694xxxx |md5ac7d6556fae123e9ea9527d8f1c94b1c |dbname |SELECT |SELECT * FROM xxx limit 200 | 6| 1048576 111111111111xxxx |SUCCESS |100101025538840xxxx |md547d09cdad4d5b5da74abaf08cba79ca0 |dbname |SELECT |SELECT * FROM xxx limit 200 |\N |\N (10 rows)
查看昨日新增的Query趨勢(shì)(按小時(shí)展示)。
SELECT to_char(a.query_start, 'HH24') AS query_start_hour, a.command_tag, COUNT(1) FROM ( SELECT DISTINCT t1.query_start, t1.digest, t1.command_tag FROM hologres.hg_query_log t1 WHERE t1.query_start >= CURRENT_DATE - INTERVAL '1 day' AND t1.query_start < CURRENT_DATE AND NOT EXISTS ( SELECT 1 FROM hologres.hg_query_log t2 WHERE t2.digest = t1.digest AND t2.query_start < CURRENT_DATE - INTERVAL '1 day' ) AND t1.digest IS NOT NULL ) AS a GROUP BY 1, 2 ORDER BY 3 DESC;
執(zhí)行結(jié)果如下,表示在昨日的11時(shí)、13時(shí)、21時(shí)分別新增了1個(gè)SELECT、1個(gè)SELECT、8個(gè)INSERT類型的Query。
query_start_hour |command_tag |count ------------------+-------------+----- 21 |INSERT | 8 11 |SELECT | 1 13 |SELECT | 1 (3 rows)
歸類慢Query的次數(shù)。
SELECT digest, command_tag, count(1) FROM hologres.hg_query_log WHERE query_start >= CURRENT_DATE - INTERVAL '1 day' AND query_start < CURRENT_DATE GROUP BY 1,2 ORDER BY 3 DESC;
查詢過去1天CPU平均耗時(shí)前十的Query。
SELECT digest, avg(cpu_time_ms) FROM hologres.hg_query_log WHERE query_start >= CURRENT_DATE - INTERVAL '1 day' AND query_start < CURRENT_DATE AND digest IS NOT NULL AND usename != 'system' AND cpu_time_ms IS NOT NULL GROUP BY 1 ORDER BY 2 DESC LIMIT 10;
查看過去一周內(nèi)存(memory_bytes)平均消耗量前十的Query。
SELECT digest, avg(memory_bytes) FROM hologres.hg_query_log WHERE query_start >= CURRENT_DATE - INTERVAL '7 day' AND query_start < CURRENT_DATE AND digest IS NOT NULL AND memory_bytes IS NOT NULL GROUP BY 1 ORDER BY 2 DESC LIMIT 10;
查看最近3小時(shí)內(nèi)每小時(shí)的Query訪問量和數(shù)據(jù)讀取總量,用于對(duì)比判斷每個(gè)小時(shí)是否有數(shù)據(jù)量變化。
SELECT date_trunc('hour', query_start) AS query_start, count(1) AS query_count, sum(read_bytes) AS read_bytes, sum(cpu_time_ms) AS cpu_time_ms FROM hologres.hg_query_log WHERE query_start >= now() - interval '3 h' GROUP BY 1;
查看與昨天同一時(shí)間對(duì)比過去3小時(shí)的數(shù)據(jù)訪問量情況,用于判斷相較于昨日是否有數(shù)據(jù)量訪問變化。
SELECT query_date, count(1) AS query_count, sum(read_bytes) AS read_bytes, sum(cpu_time_ms) AS cpu_time_ms FROM hologres.hg_query_log WHERE query_start >= now() - interval '3 h' GROUP BY query_date UNION ALL SELECT query_date, count(1) AS query_count, sum(read_bytes) AS read_bytes, sum(cpu_time_ms) AS cpu_time_ms FROM hologres.hg_query_log WHERE query_start >= now() - interval '1d 3h' AND query_start <= now() - interval '1d' GROUP BY query_date;
查詢最近時(shí)間段(如最近10分鐘)Query各階段耗時(shí)比較高的Query。您也可以根據(jù)業(yè)務(wù)需求修改具體時(shí)間,查詢目標(biāo)時(shí)間段Query各階段耗時(shí)比較高的Query。
SELECT status AS "狀態(tài)", duration AS "耗時(shí)(ms)", optimization_cost AS "優(yōu)化耗時(shí)(ms)", start_query_cost AS "啟動(dòng)耗時(shí)(ms)", get_next_cost AS "執(zhí)行耗時(shí)(ms)", duration - optimization_cost - start_query_cost - get_next_cost AS "其他耗時(shí)(ms)", query_id AS "QueryID", query::char(30) FROM hologres.hg_query_log WHERE query_start >= now() - interval '10 min' ORDER BY duration DESC, start_query_cost DESC, optimization_cost, get_next_cost DESC, duration - optimization_cost - start_query_cost - get_next_cost DESC LIMIT 100;
執(zhí)行結(jié)果如下:
狀態(tài) | 耗時(shí)(ms) | 優(yōu)化耗時(shí)(ms) | 啟動(dòng)耗時(shí)(ms) | 執(zhí)行耗時(shí)(ms) | 其他耗時(shí)(ms) | QueryID | query ---------+----------+--------------+--------------+--------------+--------------+--------------------+-------------------------------- SUCCESS | 4572 | 521 | 320 | 3726 | 5 | 6000260625679xxxx | -- /* user: wang ip: xxx.xx.x SUCCESS | 1490 | 538 | 98 | 846 | 8 | 12000250867886xxxx | -- /* user: lisa ip: xxx.xx.x SUCCESS | 1230 | 502 | 95 | 625 | 8 | 26000512070295xxxx | -- /* user: zhang ip: xxx.xx. (3 rows)
查詢最先失敗的Query。
SELECT status AS "狀態(tài)", regexp_replace(message, '\n', ' ')::char(150) AS "報(bào)錯(cuò)信息", duration AS "耗時(shí)(ms)", query_start AS "開始時(shí)間", query_id AS "QueryID", query::char(100) AS "Query" FROM hologres.hg_query_log WHERE query_start BETWEEN '2021-03-25 17:00:00'::timestamptz AND '2021-03-25 17:42:00'::timestamptz + interval '2 min' AND status = 'FAILED' ORDER BY query_start ASC LIMIT 100;
執(zhí)行結(jié)果如下:
狀態(tài) | 報(bào)錯(cuò)信息 | 耗時(shí)(ms) | 開始時(shí)間 | QueryID | Query --------+--------------------------------------------------------------------------------------------------------------------------------------------------------+-------+------------------------+-------------------+------- FAILED | Query:[1070285448673xxxx] code: kActorInvokeError msg: "[holo_query_executor.cc:330 operator()] HGERR_code XX000 HGERR_msge internal error: status { c | 1460 | 2021-03-25 17:28:54+08 | 1070285448673xxxx | S... FAILED | Query:[1016285560553xxxx] code: kActorInvokeError msg: "[holo_query_executor.cc:330 operator()] HGERR_code XX000 HGERR_msge internal error: status { c | 131 | 2021-03-25 17:28:55+08 | 1016285560553xxxx | S... (2 rows)
慢Query日志導(dǎo)出
Hologres支持使用INSERT語句將慢Query日志(hg_query_log)中的數(shù)據(jù)導(dǎo)出到您自定義的內(nèi)部表或者M(jìn)axCompute、OSS等外部表。
注意事項(xiàng)。
為了正確和高效地導(dǎo)出慢Query日志中的數(shù)據(jù),您需要注意以下幾點(diǎn)。
執(zhí)行
INSERT INTO ... SELECT ... FROM hologres.hg_query_log;
的賬號(hào),需要有hologres.hg_query_log
表的相應(yīng)訪問權(quán)限,詳情請(qǐng)參見授予查看權(quán)限。如果需要導(dǎo)出全實(shí)例的慢Query日志,則需要執(zhí)行INSERT
命令的賬號(hào)擁有Superuser或者pg_read_all_stats權(quán)限,否則查詢的hologres.hg_query_log
表數(shù)據(jù)不全,導(dǎo)致導(dǎo)出的數(shù)據(jù)不完整。query_start是慢Query日志表的索引,按照時(shí)間范圍導(dǎo)出時(shí),查詢條件請(qǐng)帶上
query_start
列來選擇時(shí)間范圍,這樣性能更好,資源消耗更少。使用
query_start
篩選時(shí)間范圍時(shí),不要在query_start
上再嵌套表達(dá)式,否則會(huì)妨礙索引命中。例如WHERE to_char(query_start, 'yyyymmdd') = '20220101';
更好的寫法應(yīng)該是:WHERE query_start >= to_char('20220101', 'yyyy-mm-dd') and query_start < to_char('20220102', 'yyyy-mm-dd');
。
示例一:導(dǎo)出至Hologres內(nèi)部表。
在Hologres中執(zhí)行如下命令將慢Query日志導(dǎo)出至query_log_download內(nèi)部表。
--Hologres SQL CREATE TABLE query_log_download ( usename text, status text, query_id text, datname text, command_tag text, duration integer, message text, query_start timestamp with time zone, query_date text, query text, result_rows bigint, result_bytes bigint, read_rows bigint, read_bytes bigint, affected_rows bigint, affected_bytes bigint, memory_bytes bigint, shuffle_bytes bigint, cpu_time_ms bigint, physical_reads bigint, pid integer, application_name text, engine_type text[], client_addr text, table_write text, table_read text[], session_id text, session_start timestamp with time zone, trans_id text, command_id text, optimization_cost integer, start_query_cost integer, get_next_cost integer, extended_cost text, plan text, statistics text, visualization_info text, query_detail text, query_extinfo text[] ); INSERT INTO query_log_download SELECT usename, status, query_id, datname, command_tag, duration, message, query_start, query_date, query, result_rows, result_bytes, read_rows, read_bytes, affected_rows, affected_bytes, memory_bytes, shuffle_bytes, cpu_time_ms, physical_reads, pid, application_name, engine_type, client_addr, table_write, table_read, session_id, session_start, trans_id, command_id, optimization_cost, start_query_cost, get_next_cost, extended_cost, plan, statistics, visualization_info, query_detail, query_extinfo FROM hologres.hg_query_log WHERE query_start >= '2022-08-03' AND query_start < '2022-08-04';
示例二:導(dǎo)出至MaxCompute外部表。
在MaxCompute側(cè)使用如下命令創(chuàng)建接收數(shù)據(jù)的表。
CREATE TABLE if NOT EXISTS mc_holo_query_log ( username STRING COMMENT '查詢的用戶名' ,status STRING COMMENT '查詢的最終狀態(tài),成功或失敗' ,query_id STRING COMMENT '查詢ID' ,datname STRING COMMENT '查詢的數(shù)據(jù)庫名' ,command_tag STRING COMMENT '查詢的類型' ,duration BIGINT COMMENT '查詢的耗時(shí)(ms)' ,message STRING COMMENT '報(bào)錯(cuò)的信息' ,query STRING COMMENT '查詢的文本內(nèi)容' ,read_rows BIGINT COMMENT '查詢讀取的行數(shù)' ,read_bytes BIGINT COMMENT '查詢讀取的字節(jié)數(shù)' ,memory_bytes BIGINT COMMENT '單節(jié)點(diǎn)峰值內(nèi)存消耗(非精確)' ,shuffle_bytes BIGINT COMMENT '數(shù)據(jù)Shuffle估計(jì)字節(jié)數(shù)(非精確)' ,cpu_time_ms BIGINT COMMENT '總的CPU時(shí)間(毫秒,非精確)' ,physical_reads BIGINT COMMENT '物理讀的次數(shù)' ,application_name STRING COMMENT '查詢應(yīng)用類型' ,engine_type ARRAY<STRING> COMMENT '查詢用到的引擎' ,table_write STRING COMMENT 'SQL改寫的表' ,table_read ARRAY<STRING> COMMENT 'SQL讀取的表' ,plan STRING COMMENT '查詢對(duì)應(yīng)的plan' ,optimization_cost BIGINT COMMENT '查詢執(zhí)行計(jì)劃的耗時(shí)' ,start_query_cost BIGINT COMMENT '查詢啟動(dòng)耗時(shí)' ,get_next_cost BIGINT COMMENT '查詢執(zhí)行耗時(shí)' ,extended_cost STRING COMMENT '查詢的其他詳細(xì)耗時(shí)' ,query_detail STRING COMMENT '查詢的其他擴(kuò)展信息(JSON格式存儲(chǔ))' ,query_extinfo ARRAY<STRING> COMMENT '查詢的其他擴(kuò)展信息(ARRAY格式存儲(chǔ))' ,query_start STRING COMMENT '查詢開始時(shí)間' ,query_date STRING COMMENT '查詢開始日期' ) COMMENT 'hologres instance query log daily' PARTITIONED BY ( ds STRING COMMENT 'stat date' ) LIFECYCLE 365; ALTER TABLE mc_holo_query_log ADD PARTITION (ds=20220803);
在Hologres側(cè)使用如下命令將慢Query日志導(dǎo)出至MaxCompute外部表。
IMPORT FOREIGN SCHEMA project_name LIMIT TO (mc_holo_query_log) FROM SERVER odps_server INTO public; INSERT INTO mc_holo_query_log SELECT usename AS username, status, query_id, datname, command_tag, duration, message, query, read_rows, read_bytes, memory_bytes, shuffle_bytes, cpu_time_ms, physical_reads, application_name, engine_type, table_write, table_read, plan, optimization_cost, start_query_cost, get_next_cost, extended_cost, query_detail, query_extinfo, query_start, query_date, '20220803' FROM hologres.hg_query_log WHERE query_start >= '2022-08-03' AND query_start < '2022-08-04';
配置項(xiàng)
為了實(shí)現(xiàn)針對(duì)性地記錄目標(biāo)Query,Hologres有如下配置項(xiàng)可供選擇。
log_min_duration_statement
配置項(xiàng)說明
修改此配置項(xiàng)僅對(duì)新Query生效,對(duì)于已經(jīng)采集的Query,則按照原默認(rèn)值展示。
只有超級(jí)用戶(Superuser)可以改變這個(gè)設(shè)置。
設(shè)置為
-1
將則表示不記錄任何查詢。為正數(shù)時(shí),最小值支持設(shè)置為100ms。使用示例
設(shè)置在慢Query日志中所有運(yùn)行時(shí)間等于或者超過
250ms
的SQL語句可以被查詢出來:-- DB級(jí)別設(shè)置,需要superuser設(shè)置 ALTER DATABASE dbname SET log_min_duration_statement = '250ms'; -- 當(dāng)前Session級(jí)別設(shè)置,普通用戶可以執(zhí)行 SET log_min_duration_statement = '250ms';
該配置項(xiàng)記錄慢Query的最短耗時(shí),系統(tǒng)默認(rèn)采集大于100ms的Query,但是查詢時(shí)默認(rèn)僅展示大于1s的Query,如需修改默認(rèn)的展示時(shí)間,可以通過該配置項(xiàng)控制。需要注意的是:
log_min_duration_query_stats
配置項(xiàng)說明
修改此配置項(xiàng)僅對(duì)新Query生效,已被記錄的Query按照原默認(rèn)值展示。
設(shè)置為
-1
則關(guān)閉對(duì)Query統(tǒng)計(jì)信息的記錄。此信息存儲(chǔ)量較高,記錄較多會(huì)降低查詢分析慢Query日志的速度,因此可以在排查具體問題時(shí)設(shè)置小于10s,否則不建議調(diào)整為更小的值。
使用示例
設(shè)置記錄大于20s的Query執(zhí)行時(shí)的統(tǒng)計(jì)信息:
--DB級(jí)別設(shè)置,需要superuser設(shè)置 ALTER DATABASE dbname SET log_min_duration_query_stats = '20s'; -- 當(dāng)前Session級(jí)別設(shè)置,普通用戶可以執(zhí)行 SET log_min_duration_query_stats = '20s';
該配置項(xiàng)記錄Query執(zhí)行時(shí)的統(tǒng)計(jì)信息,系統(tǒng)默認(rèn)記錄大于10s的Query執(zhí)行時(shí)的統(tǒng)計(jì)信息,需要注意的是:
log_min_duration_query_plan
配置項(xiàng)說明
修改此配置項(xiàng)僅對(duì)新Query生效,已被記錄的Query按照原默認(rèn)值展示。
如果某個(gè)語句的執(zhí)行時(shí)間大于或者等于設(shè)定的毫秒數(shù),那么在慢Query日志上記錄該語句的執(zhí)行計(jì)劃。
執(zhí)行計(jì)劃一般情況下可以即時(shí)地通過
explain
得到,無需特別記錄。設(shè)置為
-1
則關(guān)閉對(duì)Query執(zhí)行計(jì)劃的記錄。使用示例
設(shè)置記錄大于10s的Query日志的執(zhí)行計(jì)劃:
-- DB級(jí)別設(shè)置,需要superuser設(shè)置 ALTER DATABASE dbname SET log_min_duration_query_plan = '10s'; -- 當(dāng)前Session設(shè)置,普通用戶可以執(zhí)行 SET log_min_duration_query_plan = '10s';
該配置項(xiàng)記錄Query的執(zhí)行計(jì)劃信息,系統(tǒng)將會(huì)默認(rèn)展示大于等于10s的慢Query日志的執(zhí)行計(jì)劃,需要注意:
常見問題
問題現(xiàn)象:
在Hologres V1.1版本中,查看慢Query日志,無法顯示查詢行數(shù)、返回行數(shù)等信息。
可能原因:
慢Query日志采集不完整。
解決方法:
在Hologres V1.1.36至V1.1.49版本可以通過如下GUC參數(shù)使其顯示完整。在HologresV1.1.49及以上版本可直接顯示。
說明如果您的Hologres實(shí)例版本低于 V1.1.36,請(qǐng)您使用自助升級(jí)或加入Hologres釘釘交流群反饋,詳情請(qǐng)參見如何獲取更多的在線支持?。
--(建議)數(shù)據(jù)庫級(jí)別,一個(gè)db設(shè)置一次即可。 ALTER databse <db_name> SET hg_experimental_force_sync_collect_execution_statistics = ON; --session級(jí)別 SET hg_experimental_force_sync_collect_execution_statistics = ON;
db_name為數(shù)據(jù)庫名稱。
相關(guān)文檔
對(duì)實(shí)例中的Query進(jìn)行診斷和管理,請(qǐng)參見Query管理。