<bdo id="ks4iu"><del id="ks4iu"></del></bdo>
  • 
    <pre id="ks4iu"></pre>
  • <bdo id="ks4iu"><del id="ks4iu"></del></bdo>
    <input id="ks4iu"><em id="ks4iu"></em></input>
    
    
  • <center id="ks4iu"><cite id="ks4iu"></cite></center>
  • 首頁 > 空調(diào) >

    天天快消息!遇到慢SQL該怎么辦?(下)

    來源 | OSCHINA 社區(qū)


    (資料圖片)

    作者 | Gauss松鼠會

    原文鏈接:https://my.oschina.net/gaussdb/blog/5553522

    在數(shù)據(jù)庫的日常使用中,難免會遇到慢 SQL,遇到慢 SQL 本身并不可怕,困難之處在于如何識別慢 SQL 并對其優(yōu)化,使它不至于拖慢整個系統(tǒng)的性能,避免危害到日常業(yè)務(wù)的正常進行。

    上期我們講了索引原因、系統(tǒng)配置和資源競爭導(dǎo)致的慢 SQL,今天我們繼續(xù)分析和總結(jié)。

    目錄

    表本身包含大量數(shù)據(jù)

    SQL 語句寫得很差

    總結(jié)

    表本身包含大量數(shù)據(jù)

    盡管 openGauss 對于大的行存表處理性能非常優(yōu)秀,但表本身的數(shù)據(jù)情況依然是導(dǎo)致慢 SQL 的重要原因。一般來說,具有以下幾種情況:

    1. 表的數(shù)據(jù)量很大,且很少被緩存,導(dǎo)致語句需要掃描的元組很多;

    2. 表的數(shù)據(jù)量很大,在修改、刪除數(shù)據(jù)時需要修改較多的元組;

    3. 向表中插入的數(shù)據(jù)量很大;

    4. 業(yè)務(wù)上需要檢索出的數(shù)據(jù)量很多;

    5. 頻繁的數(shù)據(jù)修改,導(dǎo)致表中存在很多死元組(dead tuple),影響掃描性能;

    表的數(shù)據(jù)量較大導(dǎo)致的慢 SQL 問題,一般需要從業(yè)務(wù)上進行入手,直接通過修改數(shù)據(jù)庫來達到優(yōu)化慢 SQL 的目的是很難實現(xiàn)的。因此,需要用戶分析具體的業(yè)務(wù),對業(yè)務(wù)數(shù)據(jù)進行冷熱分離、分庫分表、使用分布式中間件等。如果希望在數(shù)據(jù)庫層進行優(yōu)化,則可以通過增加宿主機的內(nèi)存,進而增加 max_process_memory、shared_buffers、work_mem 等的大??;使用性能更佳的磁盤;適當(dāng)創(chuàng)建索引;使用表空間調(diào)整磁盤布局等。

    SQL 語句寫得很差

    由 SQL 語句寫法問題導(dǎo)致的慢 SQL 也相對多見,這類寫得比較差的慢 SQL 也被俗稱為 “爛 SQL”。多數(shù)情況都下,由 “爛 SQL” 導(dǎo)致的索引失效的問題較多,對于這種情況,可參考前面的描述對 SQL 語句進行改寫,使其能夠使用到索引。

    除了修改慢 SQL 使其能夠使用索引,下面還列出了幾種比較常見的、可能優(yōu)化 openGauss 數(shù)據(jù)庫性能的 SQL 改寫規(guī)則:

    改寫規(guī)則

    改寫條件

    改寫說明

    原始查詢語句示例

    改寫后語句示例

    將"select distinct *" 改寫為"select *"

    所查詢表格含唯一列或主鍵

    通過確定 tuple 無重復(fù),去掉 distinct,從而省去去重步驟,提升效率

    select distinct * from bmsql_customer limit 10;

    select * from bmsql_customer limit 10;

    將 having 子句中條件放到 where 子句中

    -

    將謂詞表達式提前,可有效縮減 group 時的數(shù)據(jù)集

    select cfg_name from bmsql_config group by cfg_name having cfg_name="1"

    select cfg_name from bmsql_config where cfg_name = "1" group by cfg_name

    簡化 where 子句中謂詞表達式

    -

    某些復(fù)雜謂詞無法有效觸發(fā) openGauss 內(nèi)的 rewrite 邏輯,無法使用索引掃描

    select o_w_id, o_d_id, o_id, o_c_id from bmsql_oorder where o_w_id + 1> 3

    select o_w_id, o_d_id, o_id, o_c_id from bmsql_oorder where o_w_id > 2

    將 order by 或 group by 中的無用列去掉

    group by 或 order by 涉及的列包含在 where 子句中的等值表達式中

    去掉無用字段,SQL 更為簡潔

    select cfg_name from bmsql_config where cfg_name="2" group by cfg_name order by cfg_name, cfg_value

    select cfg_name from bmsql_config where cfg_name = "2" order by cfg_value

    去掉 where 子句中永為真的表達式

    -

    去掉無用字段,SQL 更為簡潔

    select * from bmsql_config where 1=1 and 2=2 limit 10

    select * from bmsql_config limit 10

    將 union 轉(zhuǎn)換為 union all

    -

    避免了去重帶來的執(zhí)行代價

    select * from bmsql_config union select * from bmsql_config

    select * from bmsql_config union all select * from bmsql_config

    將 delete 語句轉(zhuǎn)換為 truncate 語句

    無 where 子句

    將 DML 語句轉(zhuǎn)換為 DDL 語句,一次性回收表空間,執(zhí)行速度更快

    delete from bmsql_config

    truncate table bmsql_config

    將 where 子句中 "or" 連接的等式轉(zhuǎn)換為 "in" 結(jié)構(gòu)

    -

    "in" 結(jié)構(gòu)可加快過濾速度

    select * from bmsql_stock where s_w_id=10 or s_w_id=1 or s_w_id=100 or s_i_id=1 or s_i_id=10

    select * from bmsql_stock where s_w_id in (1,10,100) or s_i_id in(1,10)

    將 self join 查詢拆分為效率更高兩個子查詢

    1) self join 查詢。

    2) where 子句包含相同列差值的范圍查詢。

    例如 1

    通過等值謂詞加快查詢速度

    select a.c_id from bmsql_customer a, bmsql_customer b where a.c_id - b.c_id <= 20 and a.c_id > b.c_id

    select * from (select a.c_id from bmsql_customer as a, bmsql_customer as b where trunc((a.c_id) / 20) = trunc(b.c_id / 20) and a.c_id > b.c_id union all select a.c_id from bmsql_customer as a, bmsql_customer as b where trunc((a.c_id) / 20) = trunc(b.c_id / 20 + 1) and a.c_id - b.c_id <= 20)

    對于業(yè)務(wù)系統(tǒng),SQL 語句上線之前的審計工作基本都可以覆蓋上述的場景,業(yè)內(nèi)也具備很多對 SQL 語句進行改寫的工具,不過這些工具的一些改寫規(guī)則并不是絕對意義上的等值改寫。而且,很多改寫條件對于 openGauss 來說不見得有效,因為 openGauss 在數(shù)據(jù)庫內(nèi)部也存在 rewrite 邏輯。

    DBMind 平臺會進一步演進 SQL 語句的智能改寫功能,提供給用戶在線的交互式智能查詢改寫能力,預(yù)計在未來的版本中與用戶見面。

    總結(jié)

    我們在上面已經(jīng)列出了能夠?qū)е侣?SQL 的原因,基本覆蓋了在 openGauss 上造成慢 SQL 的大多數(shù)原因。不過,one-by-one 手動地進行慢 SQL 檢查對于用戶來說工作量確實太大。故而,openGauss 的 DBMind 功能本身已經(jīng)集成了對慢 SQL 進行智能根因識別的能力,用戶可以通過運行下述命令在后臺啟動慢 SQL 根因分析功能(需要首先部署 Prometheus 以及 expoter,以便能夠采集到監(jiān)控指標):

    gs_dbmind service start-c confpath --only-run slow_query_diagnosis

    注:顯式指定 --only-run 參數(shù)可以僅啟動被選擇的 DBMind 服務(wù)項

    被診斷后的慢 SQL 會存儲在元數(shù)據(jù)庫(存放診斷結(jié)果的數(shù)據(jù)庫)中,用戶可以通過下述命令查看:

    gs_dbmind component slow_query_diagnosis show -c confpath --query SQL --start-timetimestamps0--end-timetimestamps1

    也可以通過與 Grafana 聯(lián)合來展示慢 SQL 的分析結(jié)果,DBMind 也提供了簡單的 Grafana 配置模板,可供用戶參考:

    https://github.com/opengauss-mirror/openGauss-server/blob/master/src/gausskernel/dbmind/tools/misc/grafana-template-slow-query-analysis.json

    由于openGauss 官方網(wǎng)站的發(fā)行包中的 DBMind 可能滯后于代碼托管平臺(gitee 或 github)上的最新代碼,直接編譯 openGauss 又需要花費很多的時間。故而,如果用戶只是想單純提取最新的 DBMind 功能,可以通過下面的 Linux 命令來實現(xiàn):

    gitclone -b master --depth 1 https://gitee.com/opengauss/openGauss-server.gitcdopenGauss-server/src/gausskernel/dbmind/mvtools dbmindtarzcf dbmind.tar.gz gs_dbmind dbmind

    生成的 dbmind.tar.gz 壓縮包在合適的部署位置解壓即可。

    當(dāng)然,如果用戶希望手動檢查一下慢 SQL 的原因,也可以根據(jù)附表的檢查項來檢查慢 SQL 的產(chǎn)生原因。

    附表:慢 SQL 檢查列表

    檢查項

    檢查方式(系統(tǒng)表或系統(tǒng)視圖)

    檢查方法

    語句執(zhí)行時存在鎖競爭

    dbe_perf.statement_history(start_time,finish_time, query)、pg_locks(pid, mode, locktype, grant)、pg_stat_activity(xact_start, query_start, query, pid)

    查詢在語句執(zhí)行期間是否被阻塞。

    表中死元組占比超過設(shè)定閾值

    dbe_perf.statement_history(query, dbname, schemaname)

    pg_stat_users_tables(relname, schemaname,n_live_tup, n_dead_tup)

    n_dead_tup /n_live_tup,占比超過閾值則認為表過度膨脹 (默認閾值:0.2)。

    語句掃描行數(shù)較多

    dbe_perf.statement_history(n_tuples_fetched, n_tuples_returned, n_live_tup, n_dead_tup)

    n_tuples_fetched+n_tuples_returned,超過閾值則認為過大(默認閾值:10000)。

    語句緩存命中率較低

    dbe_perf.statement_history(n_blocks_fetched, n_blocks_hit)

    n_block_hit /n_block_fetched,小于閾值則認為較低(默認閾值:0.95)

    慢 SQL (delete、insert、update) 相關(guān)表存在冗余索引

    dbe_perf.statement_history(dbname, schemaname, query), pg_stat_user_indexes(schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch)

    pg_indexes(schemaname, tablename, indexname, indexdef)

    SQL 相關(guān)表滿足:① 不是唯一索引;② (idx_scan, idx_tup_read,idx_tup_fetch)=(0,0,0);③ 索引不在數(shù)據(jù)庫的("pg_catalog", "information_schema","snapshot", "dbe_pldeveloper")schema 下。如果滿足則認為次索引為冗余索引,否則為有效索引。

    更新數(shù)據(jù)量較多

    dbe_perf.statement_history(query, n_tuples_updated)

    pg_stat_user_tables(n_live_tup, n_dead_tup)

    n_tuples_updated 超過閾值則認為更新數(shù)據(jù)量較多(默認閾值:1000)。

    插入數(shù)據(jù)量較多

    dbe_perf.statement_history(query, n_tuples_inserted)

    pg_stat_user_tables(n_live_tup, n_dead_tup)

    n_tuples_inserted 超過閾值則認為插入數(shù)據(jù)量較多(默認閾值:1000)。

    刪除數(shù)據(jù)量較多

    dbe_perf.statement_history(query, n_tuples_deleted)

    pg_stat_user_tables(n_live_tup, n_dead_tup)

    n_tuples_deleted 超過閾值則認為刪除數(shù)據(jù)量較多(默認閾值:1000)。

    相關(guān)表索引個數(shù)較多

    pg_stat_user_indexes(relname,schemaname, indexrelname)

    如果表中索引數(shù)大于閾值并且索引與字段數(shù)比率超過設(shè)定閾值,則認為索引數(shù)較多(索引個數(shù)閾值:3,比率默認閾值:0.6)。

    執(zhí)行語句發(fā)生落盤(外排序)行為

    dbe_perf.statement(sort_count, sort_spilled_count, sort_mem_used, hash_count, hash_spilled_count, hash_ued_mem, n_calls)

    分析指標判斷是否有 hash 或者 order 導(dǎo)致的落盤行為,主要邏輯為:

    1 如果 sort_count 或者 hash_count 不為 0,sort_mem_used 或者 hash_mem_used 為 0,則此 SQL 一定發(fā)生了落盤行為;

    2 如果 sort_spilled_count 或者 hash_spilled_count 不為 0,則執(zhí)行可能發(fā)生落盤行為;

    語句執(zhí)行期間相關(guān)表正在執(zhí)行 AUTOVACUUM 或 AUTOANALYZE 操作

    dbe_perf.statement_history(start_time, finish_time, query)

    pg_stat_user_tables(last_autovacuum, last_autoanalyze)

    執(zhí)行 SQL 期間,正在發(fā)生 vacuum 或者 analyze 行為。

    數(shù)據(jù)庫 TPS 較大

    dbe_perf.statement_history(start_time, finish_time)

    pg_stat_database(datname, xact_commit, xact_rolback)

    相對于正常業(yè)務(wù)時的 TPS,當(dāng)前 TPS 增長較大,則認為數(shù)據(jù)庫 TPS 較大;TPS 短期內(nèi)增長異常則認為是業(yè)務(wù)風(fēng)暴。

    IOWait 指標大于設(shè)定閾值

    系統(tǒng) IOWait 指標異常升高

    IOWait 大于用戶設(shè)定閾值(默認閾值:10%)

    IOPS 指標大于設(shè)定閾值

    系統(tǒng) IOPS 指標異常

    IOPS 指標大于用戶設(shè)定閾值(默認閾值:1000)。

    load average 指標大于設(shè)定閾值

    系統(tǒng) load average 指標異常

    load average 與服務(wù)器邏輯核數(shù)比率大于用戶設(shè)定閾值(默認閾值:0.6)。

    CPU USAGE 指標大于設(shè)定閾值

    系統(tǒng) CPU USAGE 指標異常

    CPU USAGE 指標大于用戶設(shè)定閾值(默認閾值:0.6)。

    IOUTILS 指標大于設(shè)定閾值

    系統(tǒng) IOUTILS 指標異常

    IOUTILS (磁盤利用率) 大于用戶設(shè)定閾值(默認閾值:0.5)。

    IOCAPACITY 指標大于設(shè)定閾值

    系統(tǒng) IO CAPACITY 指標異常

    IOCAPACITY (IO 吞吐量) 大于用戶設(shè)定閾值 (默認閾值:50MB/s)。

    IODELAY 指標大于設(shè)定閾值

    系統(tǒng) IO DELAY 指標異常

    IO DELAY(IO 延遲)大于用戶設(shè)定閾值(默認閾值:50ms)。

    網(wǎng)卡丟包率

    系統(tǒng)網(wǎng)卡丟包率異常

    NETWORK DROP RATE 大于用戶設(shè)定閾值(默認 0 閾值:0.01)。

    網(wǎng)卡錯誤率

    系統(tǒng)網(wǎng)卡錯誤率異常

    NETWORK ERROR RATE 大于用戶設(shè)定閾值(默認閾值:0.01)。

    線程池占用量異常

    dbe_perf.global_threadpool_status

    數(shù)據(jù)庫線程池使用率大于閾值(默認閾值:0.95)

    連接池占用量異常

    pg_settings.max_connections,pg_stat_activity

    數(shù)據(jù)庫連接池占用率大于閾值(默認閾值:0.8)

    雙寫延遲較大

    dbe_perf.wait_events

    雙寫延遲大于閾值(默認閾值:100us)

    表長時間未更新

    pg_stat_user_tables

    表未更新時長超過閾值(默認閾值:60s)

    checkpoint 效率低(本規(guī)則僅作為粗略判斷)

    pg_stat_bgwriter

    數(shù)據(jù)庫 buffers_backend 與(buffers_clean+buffers_checkpoint)占比小于閾值(默認閾值:1000)

    主備復(fù)制效率較低

    pg_stat_replication

    主備 write_diff、replay_diff、sent_diff 超過閾值(默認閾值:500000)

    執(zhí)行計劃存在異常 seqscan 算子

    執(zhí)行計劃

    seqscan 算子代價與總代價比率超過閾值(默認閾值:0.3),此特征也會判斷是否缺少相關(guān)索引。

    執(zhí)行計劃存在異常 nestloop 算子

    執(zhí)行計劃

    nestloop 算子代價與總代價比率超過閾值(默認閾值:0.3)并且進行 nestloop 的結(jié)果集行數(shù)超過閾值(默認閾值:10000)。

    執(zhí)行計劃存在異常 hashjoin 算子

    執(zhí)行計劃

    hashjoin 算子代價與總代價比率超過閾值(默認閾值:0.3)并且進行 hashjoin 的結(jié)果集小于閾值(默認閾值:10000)。

    執(zhí)行計劃存在異常 groupagg 算子

    執(zhí)行計劃

    groupagg 算子代價與總代價比率超過閾值(默認閾值:0.3)并且執(zhí)行 groupagg 的行數(shù)超過閾值(默認閾值:10000)。

    SQL 寫法不優(yōu)

    SQL 文本、pg_stat_user_tables

    SQL 寫法不優(yōu)導(dǎo)致執(zhí)行性能較差

    SQL 執(zhí)行被定時任務(wù)影響

    pg_job,

    dbe_perf.statement_history

    定時任務(wù)執(zhí)行影響了 SQL 執(zhí)行性能,考慮調(diào)整定時任務(wù)時間,避免產(chǎn)生影響。

    執(zhí)行計劃生成時間較長

    dbe_perf.statement_history

    SQL 執(zhí)行計劃生成時間較長。

    參考資料:

    [1].https://www.2ndquadrant.com/en/blog/managing-freezing/

    [2]. http://mysql.taobao.org/monthly/2016/06/03/

    [3].https://www.2ndquadrant.com/en/blog/basics-of-tuning-checkpoints/

    [4]. https://lwn.net/Articles/591723/

    [5].https://dev.mysql.com/doc/refman/8.0/en/glossary.html

    [6].https://github.com/opengauss-mirror/openGauss-server/tree/master/src/gausskernel/dbmind

    END

    PG已碾過MySQL,它真正的對手是Oracle

    這里有最新開源資訊、軟件更新、技術(shù)干貨等內(nèi)容

    點這里 ↓↓↓ 記得 關(guān)注? 標星? 哦~

    責(zé)任編輯:Rex_08

    推薦閱讀
    欧美国产在线一区,免费看成年视频网页,国产亚洲福利精品一区,亚洲一区二区约美女探花
    <bdo id="ks4iu"><del id="ks4iu"></del></bdo>
  • 
    <pre id="ks4iu"></pre>
  • <bdo id="ks4iu"><del id="ks4iu"></del></bdo>
    <input id="ks4iu"><em id="ks4iu"></em></input>
    
    
  • <center id="ks4iu"><cite id="ks4iu"></cite></center>
  • 主站蜘蛛池模板: 亚洲成a人v欧美综合天堂麻豆| 国产成人麻豆亚洲综合无码精品| 免费观看a级毛片| 一本色道久久综合网| 精品福利视频一区二区三区| 男男性彩漫漫画无遮挡| 性生活免费大片| 六月婷婷中文字幕| www.日本xxxx| 色偷偷色噜噜狠狠网站久久| 日本丶国产丶欧美色综合| 国产美女做a免费视频软件| 人妻中文字幕乱人伦在线| av在线亚洲男人的天堂| 泰国一级淫片免费看| 国产美女牲交视频| 亚洲人成伊人成综合网久久| 人人揉人人爽五月天视频| 日韩美女在线视频网站免费观看| 国产在线精品一区在线观看| 久久亚洲国产精品123区| 脱了美女内裤猛烈进入gif| 少妇激情av一区二区| 人人妻人人爽人人澡AV| 91天堂素人精品系列网站| 末成年女a∨片一区二区 | 国产丰满岳乱妇在线观看| 中文字幕日韩高清版毛片| 精品国产三级a在线观看| 大战bbw丰满肥女tub| 亚洲国产精品久久网午夜| 4hu四虎最新免费地址| 无码精品久久久久久人妻中字| 国产成人精品影院狼色在线| 久久在精品线影院精品国产| 久碰人澡人澡人澡人澡人视频| 日本欧美中文字幕| 午夜无码人妻av大片色欲| 99精品国产在热久久无码| 欧美亚洲桃花综合| 国产三级精品三级在线专区 |