最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SQL性能優(yōu)化之壓測404的根因追查與解決方案

 更新時(shí)間:2026年03月25日 08:29:30   作者:G探險(xiǎn)者  
測試人員對任務(wù)列表查詢接口進(jìn)行并發(fā)壓測時(shí),出現(xiàn)大量 404 響應(yīng)錯(cuò)誤,經(jīng)初步排查,這些 404 并非業(yè)務(wù)邏輯主動返回,而是接口響應(yīng)超時(shí)后由網(wǎng)關(guān)/Nginx 拋出的超時(shí)錯(cuò)誤,下面我們就來看看如何優(yōu)化這一問題吧

今天聊一聊sql優(yōu)化的一則案例分析。

適用數(shù)據(jù)庫:達(dá)夢(DM8)/ MySQL

場景:任務(wù)列表查詢接口 work_hour_task 壓力測試

一、背景

測試人員對任務(wù)列表查詢接口進(jìn)行并發(fā)壓測時(shí),出現(xiàn)大量 404 響應(yīng)錯(cuò)誤。經(jīng)初步排查,這些 404 并非業(yè)務(wù)邏輯主動返回,而是接口響應(yīng)超時(shí)后由網(wǎng)關(guān)/Nginx 拋出的超時(shí)錯(cuò)誤。

觸發(fā)鏈路如下:

SQL 慢查詢(全表掃描 + N+1 子查詢 + filesort)
  → 接口響應(yīng)時(shí)間飆升
  → 壓測并發(fā)請求大量堆積
  → 網(wǎng)關(guān)請求排隊(duì)超時(shí)
  → 返回 404

二、問題 SQL

原始 SQL(MySQL 版本)

EXPLAIN SELECT
    t.id, t.tenant_id, t.task_name, t.is_project_task, t.team_code, t.project_code,
    t.task_type, t.task_sub_type, t.responsible_person_code, t.work_hours, t.estimate_work_hours,
    t.task_desc, t.process, t.plan_start_date, t.plan_end_date, t.task_source,
    t.actual_start_time, t.actual_end_time, t.related_team_code, t.rel_id,
    t.STATUS, t.ext_info, t.version, t.deleted,
    t.created_by, t.created_time, t.updated_by, t.updated_time
FROM work_hour_task t
WHERE t.deleted = 0
  AND (
    t.team_code IN ('webDev')
    OR EXISTS (
      SELECT 1 FROM work_hour_task_related_team tr
      WHERE tr.task_rel_id = t.rel_id
        AND tr.deleted = 0
        AND tr.team_code IN ('webDev')
        AND tr.TENANT_ID = 'hkbank'
    )
  )
  AND t.TENANT_ID = 'hkbank'
ORDER BY t.created_time DESC
LIMIT 15

達(dá)夢版本結(jié)構(gòu)基本一致,WHERE 條件中額外使用了 FIND_IN_SET 函數(shù)代替 EXISTS 子查詢。

三、執(zhí)行計(jì)劃解讀

MySQL 版本執(zhí)行計(jì)劃

idselect_typetypekeyrowsExtra
1PRIMARYALLNULL1233Using where; Using filesort
2DEPENDENT SUBQUERYeq_refuk_task_team_del1Using index condition; Using where

達(dá)夢版本執(zhí)行計(jì)劃

節(jié)點(diǎn)類型描述
NSET2 → PRJT2 → SORT3結(jié)果集 → 投影 → 排序存在額外排序開銷
UNION FOR OR2OR 條件拆成兩路掃描兩路各自回表,代價(jià)翻倍
BLKUP2 × 2BOOKMARK LOOKUP兩路均存在回表
SSEK2 × 2二級索引 seek其中一路因 FIND_IN_SET 索引失效

四、三大核心問題

問題一:全表掃描(type = ALL)

主表 t 有 3 個(gè)候選索引(idx_task_teamidx_task_page_core、idx_task_count_core),但優(yōu)化器最終 key = NULL,全部放棄,被迫全表掃描 1233 行。

根本原因: WHERE 條件中對列使用了函數(shù)(FIND_IN_SET)或存在關(guān)聯(lián)子查詢(EXISTS),優(yōu)化器無法利用索引進(jìn)行范圍掃描。

問題二:DEPENDENT SUBQUERY(N+1 問題)

EXISTS 子查詢的 select_typeDEPENDENT SUBQUERY,意味著它依賴外層主表的每一行逐行觸發(fā)執(zhí)行。

主表掃描 1233 行 × 子查詢執(zhí)行 1233 次 = I/O 實(shí)際放大 1233 倍

子查詢雖然單次走了唯一索引(eq_ref,rows=1),但積累后總代價(jià)極高,這是典型的 N+1 問題

問題三:Using filesort(額外排序)

ORDER BY t.created_time DESC 無法利用現(xiàn)有索引完成排序,數(shù)據(jù)庫須在內(nèi)存或磁盤中對全量結(jié)果集做額外排序。高并發(fā)壓測時(shí),排序操作大量占用 CPU 和內(nèi)存,進(jìn)一步拖慢響應(yīng)時(shí)間。

五、優(yōu)化方案

改寫思路:兩段式查詢

將原來「一條復(fù)雜 SQL 承包所有邏輯」的寫法,拆分為兩步:

  • 第一步(ID 收集層):輕量查詢先收集符合條件的 task id 列表,用 UNION ALL 分別處理兩種匹配條件,各自加 ORDER BY + LIMIT,合并后取 Top N。
  • 第二步(明細(xì)查詢層):用主鍵 IN (id1, id2, ...) 查詢完整字段,走主鍵索引,無子查詢,無 filesort。

這種「分步查詢」模式是處理 OR + 子查詢 + 排序分頁 組合場景的標(biāo)準(zhǔn)實(shí)踐,徹底解耦了「找哪些記錄」和「取這些記錄的字段」兩個(gè)問題。

優(yōu)化后 SQL(MySQL 版本)

-- 第二步:用主鍵 IN 查詢明細(xì),消除子查詢和 filesort
SELECT
    id, tenant_id, task_name, is_project_task, team_code, project_code,
    task_type, task_sub_type, responsible_person_code, work_hours, estimate_work_hours,
    task_desc, process, plan_start_date, plan_end_date, task_source,
    actual_start_time, actual_end_time, related_team_code, rel_id,
    STATUS, ext_info, version, deleted,
    created_by, created_time, updated_by, updated_time
FROM work_hour_task
WHERE id IN (1942, 1941, 1940, 1939, 1938, 1937, 1936, 1935,
             1934, 1933, 1932, 1931, 1930, 1929, 1928)
  AND deleted = 0
  AND TENANT_ID = 'hkbank'

優(yōu)化后執(zhí)行計(jì)劃

idselect_typetypekeyrowsExtra
1SIMPLErangePRIMARY15Using where

達(dá)夢版本額外改寫

達(dá)夢原 SQL 中 FIND_IN_SET 將函數(shù)施加于列上導(dǎo)致索引失效,需在應(yīng)用層將參數(shù)預(yù)先拆分:

-- 改前(索引失效)
OR FIND_IN_SET(?, RELATED_TEAM_CODE) > 0
-- 改后(應(yīng)用層拆分參數(shù)后傳入,索引可正常使用)
OR t.related_team_code IN (?, ?, ?)

推薦覆蓋索引

-- MySQL
ALTER TABLE work_hour_task
ADD INDEX idx_covering (TENANT_ID, deleted, team_code, created_time DESC);

-- 達(dá)夢
CREATE INDEX idx_covering
ON work_hour_task (TENANT_ID, deleted, team_code, created_time DESC);

六、優(yōu)化前后對比

指標(biāo)優(yōu)化前優(yōu)化后
select_typePRIMARY + DEPENDENT SUBQUERYSIMPLE
type(掃描類型)ALL(全表掃描)?range(索引范圍掃描)?
key(命中索引)NULL(全部放棄)?PRIMARY(主鍵)?
rows(掃描行數(shù))1233 行 × 子查詢 1233 次 ?15 行 ?
ExtraUsing filesort ?Using where ?
行數(shù)降幅下降 98.8%

優(yōu)化前執(zhí)行路徑:全表掃描 1233 行 → 逐行觸發(fā)子查詢(× 1233 次)→ filesort 排序 → 取 Top 15

優(yōu)化后執(zhí)行路徑:主鍵 range 掃描 15 行 → 直接返回(無子查詢,無排序)

七、經(jīng)驗(yàn)總結(jié)與規(guī)范建議

本次問題根因清單

#根因影響解決方式
1FIND_IN_SET / EXISTS 對列施函數(shù)索引全部失效,退化為全表掃描改為 IN (?) 或應(yīng)用層預(yù)處理
2DEPENDENT SUBQUERY(N+1)子查詢隨主表每行觸發(fā),I/O 放大 N 倍分步查詢或改寫為 JOIN
3Using filesort全量結(jié)果集額外排序,高并發(fā)時(shí) CPU 飆升建包含 ORDER BY 字段的覆蓋索引
4缺少覆蓋索引索引命中后仍大量回表取字段建聯(lián)合覆蓋索引,字段順序:過濾列 + 排序列

SQL 開發(fā)規(guī)范建議

禁止在 WHERE 條件的列上直接使用函數(shù)FIND_IN_SET、DATE()、YEAR() 等),改為在參數(shù)側(cè)做處理,保持列的"裸露"。

慎用 EXISTS / IN 關(guān)聯(lián)子查詢,考慮改寫為 JOIN 或分步查詢,避免產(chǎn)生 DEPENDENT SUBQUERY。

分頁列表接口推薦「兩段式查詢」:先查 id 列表(輕查詢,走索引),再用主鍵 IN 查完整字段,兩步走比一步復(fù)雜查詢更可控。

新建索引需覆蓋 WHERE 過濾字段 + ORDER BY 字段,減少回表和 filesort,字段順序按選擇性從高到低排列。

上線前必須通過 EXPLAIN 驗(yàn)證執(zhí)行計(jì)劃,重點(diǎn)關(guān)注:

  • type 不得為 ALL
  • Extra 不得出現(xiàn) Using filesort / Using temporary

壓測出現(xiàn)大量非業(yè)務(wù) 404 時(shí),優(yōu)先排查接口響應(yīng)時(shí)間和數(shù)據(jù)庫慢查詢?nèi)罩?,而非只看?yīng)用層錯(cuò)誤日志。

執(zhí)行計(jì)劃關(guān)鍵字速查

字段危險(xiǎn)值(需優(yōu)化)目標(biāo)值
typeALL(全表)range / ref / eq_ref / const
keyNULL(未用索引)命中具體索引名
rows遠(yuǎn)大于實(shí)際返回行數(shù)接近實(shí)際返回行數(shù)
ExtraUsing filesort / Using temporaryUsing index(覆蓋索引最佳)
select_typeDEPENDENT SUBQUERYSIMPLE / PRIMARY

總結(jié)

這次優(yōu)化的核心收獲是:慢不一定在業(yè)務(wù)代碼里,404 也不一定是路由問題。當(dāng)壓測出現(xiàn)大量超時(shí)類 404 時(shí),第一步應(yīng)該打開慢查詢?nèi)罩?,?EXPLAIN 拿出來看。

記住三個(gè)關(guān)鍵詞:全表掃描、N+1、filesort。這三者任意一個(gè)在高并發(fā)下都足以拖垮接口,三個(gè)疊加則必然超時(shí)。

優(yōu)化的本質(zhì)不是"加索引"這么簡單,而是要理解優(yōu)化器的決策邏輯——讓 WHERE 條件能走索引,讓子查詢不隨主表行數(shù)膨脹,讓 ORDER BY 不產(chǎn)生額外排序,三點(diǎn)都滿足,性能自然就上去了。

到此這篇關(guān)于SQL性能優(yōu)化之壓測404的根因追查與解決方案的文章就介紹到這了,更多相關(guān)SQL壓測404錯(cuò)誤排查與解決內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MySQL性能優(yōu)化之索引優(yōu)化與查詢優(yōu)化

    MySQL性能優(yōu)化之索引優(yōu)化與查詢優(yōu)化

    在數(shù)據(jù)庫優(yōu)化中,索引優(yōu)化和查詢優(yōu)化是兩個(gè)非常重要的方面,通過合理地使用索引,可以顯著提高查詢效率,這篇文章主要介紹了MySQL性能優(yōu)化之索引優(yōu)化與查詢優(yōu)化的相關(guān)資料,需要的朋友可以參考下
    2025-12-12
  • MySQL實(shí)現(xiàn)清空分區(qū)表單個(gè)分區(qū)數(shù)據(jù)

    MySQL實(shí)現(xiàn)清空分區(qū)表單個(gè)分區(qū)數(shù)據(jù)

    這篇文章主要介紹了MySQL實(shí)現(xiàn)清空分區(qū)表單個(gè)分區(qū)數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 簡單了解mysql方言dialect

    簡單了解mysql方言dialect

    這篇文章主要介紹了簡單了解數(shù)據(jù)庫方言dialect,數(shù)據(jù)庫方言也是如此,MySQL 是一種方言,Oracle 也是一種方言,MSSQL 也是一種方言,他們之間在遵循 SQL 規(guī)范的前提下,都有各自的擴(kuò)展特性,需要的朋友可以參考下
    2019-07-07
  • MySQL中臨時(shí)表的基本創(chuàng)建與使用教程

    MySQL中臨時(shí)表的基本創(chuàng)建與使用教程

    這篇文章主要介紹了MySQL中臨時(shí)表的基本創(chuàng)建與使用教程,注意臨時(shí)表中數(shù)據(jù)的清空問題,需要的朋友可以參考下
    2015-12-12
  • mysql error 1071: 創(chuàng)建唯一索引時(shí)字段長度限制的問題

    mysql error 1071: 創(chuàng)建唯一索引時(shí)字段長度限制的問題

    這篇文章主要介紹了mysql error 1071: 創(chuàng)建唯一索引時(shí)字段長度限制的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 一文詳解MySQL的并發(fā)控制

    一文詳解MySQL的并發(fā)控制

    無論何時(shí)只要有多個(gè)查詢需要在同一時(shí)刻修改數(shù)據(jù),都會產(chǎn)生并發(fā)控制問題,MySQL可以在兩個(gè)層面進(jìn)行并發(fā)控制,服務(wù)器層和存儲引擎層,下面這篇文章主要給大家介紹了關(guān)于MySQL并發(fā)控制的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • MySQL如何生成自增的流水號

    MySQL如何生成自增的流水號

    這篇文章主要介紹了MySQL如何生成自增的流水號問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • MySQL使用ReplicationConnection導(dǎo)致連接失效解決

    MySQL使用ReplicationConnection導(dǎo)致連接失效解決

    這篇文章主要為大家介紹了MySQL使用ReplicationConnection導(dǎo)致連接失效問題分析解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • mysql主鍵id的生成方式(自增、唯一不規(guī)則)

    mysql主鍵id的生成方式(自增、唯一不規(guī)則)

    本文主要介紹了mysql主鍵id的生成方式,主要包括兩種生成方式,文中通過代碼示例介紹的非常詳細(xì),感興趣的可以了解一下
    2021-09-09
  • MYSQL定時(shí)清除備份數(shù)據(jù)的具體操作

    MYSQL定時(shí)清除備份數(shù)據(jù)的具體操作

    這篇文章主要給大家介紹了關(guān)于MYSQL定時(shí)清除備份數(shù)據(jù)的具體操作,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用MYSQL具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06

最新評論

丰宁| 方正县| 阿克陶县| 河源市| 台东市| 华阴市| 防城港市| 邵武市| 伊金霍洛旗| 庆云县| 保定市| 秦安县| 建德市| 贵南县| 天门市| 姜堰市| 吉安市| 雷州市| 桓仁| 乌苏市| 乐至县| 泸西县| 宁陕县| 怀安县| 宝山区| 怀集县| 三原县| 和田市| 岳阳县| 九龙县| 九江市| 民丰县| 麟游县| 宁远县| 六安市| 阿拉善右旗| 塔城市| 濉溪县| 浮梁县| 镶黄旗| 巩义市|