Mysql深入學習:慢sql執行

目錄

慢查詢日志

慢查詢主要步驟

11種慢查詢的場景分析

場景一:SQL 沒有建立索引

場景二:索引未生效的典型原因

場景三:LIMIT 深分頁導致性能下降

場景四:單表數據量過大導致 SQL 性能下降

場景五:ORDER BY 出現文件排序導致 SQL 變慢

場景六:GROUP BY 使用臨時表,SQL 性能受影響

場景七:DELETE + IN 子查詢無法走索引,導致性能下降

場景八:多表 JOIN 或子查詢層級太多

場景九:IN 中元素過多,影響 SQL 性能

場景十:SQL 長時間無響應,背后可能是“拿不到鎖”

場景十一:SQL 性能下降,罪魁禍首竟是“臟頁”

如何優化臟頁相關性能問題?


慢查詢日志

Msql的慢查詢日志是Mysql的一種日志記錄

慢查詢日志主要通過long_query_time時長來決定哪些內容會被記入慢查詢日志

慢查詢日志的主要作用:收集慢sql隨后通過explain進行全面日志

需要注意,收集慢查詢語句十分耗性能的,一般來說生產是不會收集的,但是能夠在測試環境開啟,用戶模擬分析的執行計劃中,優化sql語句下面是一些關鍵參數的設置

  • slow_query_log:控制慢查詢日志的開關。設置成 1,日志就開啟;設置成 0,日志就關閉。
  • log-slow-queries(舊版本 5.6 以下使用)和slow-query-log-file(5.6 及以上版本使用):這兩個參數用來指定慢查詢日志的保存位置。如果不設置,系統會自動生成一個默認文件,名字是 “主機名 - slow.log”。
  • long_query_time:慢查詢閾值:它決定了什么樣的查詢算慢查詢,只要 SQL 語句執行時間超過這里設置的時長,就會被記錄到日志里。
  • log_queries_not_using_indexes:這是個可選參數,打開后,沒命中索引的查詢語句也會被記錄下來。
  • log_output:用來選擇日志保存方式。有 FILE(快) , TABLE(滿) 兩種方式保持日志。設置成FILE,日志就存到文件里,這是默認方式;設置成 TABLE,日志會存到數據庫的mysql.slow_log表里。也可以同時用兩種方式,寫成FILE,TABLE。不過,存到數據庫表比存到文件更費資源,如果既想開慢查詢日志,又想數據庫跑得快,建議優先把日志存到文件里。

慢查詢配置的相關查找

mysql> show VARIABLES like '%slow_query_log%';
+---------------------+-----------------------------------------------------------+
| Variable_name ? ? ? | Value ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
+---------------------+-----------------------------------------------------------+
| slow_query_log ? ? ?| OFF ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
| slow_query_log_file | d:\java\mysql-5.7.28-winx64\data\DEEP-2020AEBKQR-slow.log |
+---------------------+-----------------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)mysql> show VARIABLES like 'long_query_time%';
+-----------------+-----------+
| Variable_name ? | Value ? ? |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set, 1 warning (0.00 sec)SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;

需要注意,修改全局參數后,當前連接會話仍使用舊值,需新建會話才會生效

查看慢查詢例子

展示所有的慢查詢日志的內容

mysql> SHOW GLOBAL STATUS LIKE '%slow_queries%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Slow_queries ?| 1 ? ? |
+---------------+-------+
1 row in set (0.00 sec)

相關日志解讀

Time ? ? ? ? ? ? ? ? Id Command ? ?Argument
// Time: 2025-05-11T10:33:05.581135Z
// User@Host: root[root] @ localhost [::1] ?Id: ? ?10
// Query_time: 5.002170 ?Lock_time: 0.000000 Rows_sent: 1 ?Rows_examined: 0
SET timestamp=1746959585;
select sleep(5);
  • User@Host:表示用戶和慢查詢的連接地址(root 用戶,localhost地址,Id為 9)
  • Query_time:表示 SQL 查詢的耗時,單位為秒。Lock_time:表示獲取鎖的時間,單位為秒。Rows_sent:表示發送給客戶端的行數。Rows_examined:表示服務器層檢查的行數
  • SET timestamp:表示慢 SQL 記錄時的時間戳
  • select sleep(5);:最后一行表示慢查詢 SQL 語句

慢查詢主要步驟

慢查詢主要一開一下三個命令以及步驟EXPLAIN,OPTIMIZER_TRACE3.PROFILE

深度分頁的例子

700萬分頁的例子

mysql> select * from store.my_order order by id limit 7000000,1;
+---------+-------------+------------+----------+-------------+--------------+---------------------+
| id ? ? ?| customer_id | product_id | quantity | total_price | order_status | created_at ? ? ? ? ?|
+---------+-------------+------------+----------+-------------+--------------+---------------------+
| 7000001 | ? ? ?765891 | ? ? ? ? ?1 | ? ? ? ?9 | ? ? ? ? 666 | ? ? ? ? ? ?0 | 2023-08-25 17:25:43 |
+---------+-------------+------------+----------+-------------+--------------+---------------------+
1 row in set (1.88 sec)

執行時間花費了接近兩秒,完全就是一個慢sql

第一步EXPLAIN

在某個SQL語句的執行之前添加EXPLAIN。就能獲取到所有需要的數據

在上面,我們主要分析Extra列以及TYPE的關鍵列,還有key也嫩展示使用到的索引

但是如果EXPLAIN不能查看出明顯的區別,就要使用OPTIMIZER_TRACE

第二步OPTIMIZER_TRACE

這個關鍵字的主要作用是用于深度解析sql優化器的決策邏輯,結合EXPLAIN可以稱為調優閉環

這個關鍵字主要分析優化器做出的各種抉擇(例如各種計算開銷,各種轉換,訪問表的方式)

  • 首先通過EXPLAIN篩選問題
  • 隨后通過OPTIMIZER——TRACE準確定位問題根本

首先開啟


//開啟
SET optimizer_trace="enabled=on";?
//關閉
SET optimizer_trace="enabled=off"; ?

隨后執行sql語句以及查看OPTIMIZER _TRACE結果


SELECT * FROM my_customer where name like 'c%' limit 1000000,1;mysql> SELECT * FROM information_schema.OPTIMIZER_TRACE;
***** 1. row?*******QUERY: SELECT * FROM my_customer where name like 'c%' limit 1000000,1TRACE: {"steps": [{...省略部分內容"rows_estimation": [{"table": "my_customer","range_analysis": {"table_scan": {"rows": 995164,"cost": 203809},...省略部分內容"analyzing_range_alternatives": {"range_scan_alternatives": [{"index": "my_customer_name_IDX","ranges": ["c\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000 <= name <= c"],"index_dives_for_eq_ranges": true,"rowid_ordered": false,"using_mrr": false,"index_only": false,"rows": 497582,"cost": 597099,"chosen": false,"cause": "cost"}],...省略部分內容"considered_execution_plans": [{"plan_prefix": [],"table": "my_customer","best_access_path": {"considered_access_paths": [{"rows_to_scan": 995164,"access_type": "scan","resulting_rows": 995164,"cost": 203807,"chosen": true}]},...省略部分內容
}

分析階段

1.首先我們查看row_estimation部分

在下面有range_analysis里里面,table_scan指出進行全表掃描需要讀取995,164行數據,成本為(203,809)。

接著在potential_range_indexes中分析了可能使用的索引。

其中只有my_customer_name_IDX是可以用的,但, 即使使用這個索引,預估的行數是497,582(大約一半的數據),而其成本是 ( 597,099)。

盡管 索引掃描行數( 497,582 ),少于全表掃描 (995,164 ),但是由于成本更高 ( 597,099) ,因此,索引掃描 未被選中。

2.隨后再查看considered_execution_plans部分

在這里,MySQL考慮了不同的執行計劃,并最終選擇了對my_customer表進行訪問的最佳路徑。

最佳訪問路徑顯示,雖然它確實考慮了使用索引my_customer_name_IDX,但由于成本問題(cost: 597,099 vs cost: 203,807),最終還是選擇了全表掃描(access_type: scan)。

綜上所述,MySQL優化器決定進行全表掃描的主要原因是基于成本估算的結果。

盡管索引my_customer_name_IDX能夠減少需要掃描的行數,但由于某些原因(推斷因為回表原因),MySQL認為全表掃描是更有效的策略。

這通常發生在索引對于特定查詢的選擇性不足時,即使用索引并不能顯著減少需要檢查的數據量或計算的成本。

但是如果PROFILE也如果解決不了的話,就要用最后的秘訣:PROFILE了

第三步PROFILE

首先開啟PROFILE

set session profiling = 1;

生產環境中,可能會需要加大profile的隊列,保證想要查看的 PROFILE 結果還保存著,因此可以用如下操作來增加 PROFILE 的隊列大小


set session profiling_history_size = 50;

執行了要分析的SQL之后,執行下面的命令就能查看到PROFILES了


mysql> show profiles;
+----------+------------+----------------------------------------------------------+
| Query_ID | Duration ? | Query ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
+----------+------------+----------------------------------------------------------+
| ? ? ? ?1 | 0.00010200 | set session profiling_history_size = 50 ? ? ? ? ? ? ? ? ?|
| ? ? ? ?2 | 0.00012500 | select * from my_order order by id limit 100,1 ? ? ? ? ? |
| ? ? ? ?3 | 0.00145300 | select * from store.my_order order by id limit 100,1 ? ? |
| ? ? ? ?4 | 2.86402600 | select * from store.my_order order by id limit 7000000,1 |
+----------+------------+----------------------------------------------------------+
4 rows in set, 1 warning (0.00 sec)

就是查看具體的查詢的詳細的分析


SHOW PROFILE FOR QUERY 3; -- 查詢 Query_ID=3 的詳細信息
SHOW PROFILE FOR QUERY 4; -- 查詢 Query_ID=4 的詳細信息

隨后就會輸出結果,包括這個語句執行的各個部分的耗時

mysql> show profile block io,cpu,memory,source for query 3;
+----------------------+----------+----------+------------+--------------+---------------+----------------------------+----------------------+-------------+
| Status ? ? ? ? ? ? ? | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | Source_function ? ? ? ? ? ?| Source_file ? ? ? ? ?| Source_line |
+----------------------+----------+----------+------------+--------------+---------------+----------------------------+----------------------+-------------+
| starting ? ? ? ? ? ? | 0.000054 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | NULL ? ? ? ? ? ? ? ? ? ? ? | NULL ? ? ? ? ? ? ? ? | ? ? ? ?NULL |
| checking permissions | 0.000003 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | check_access ? ? ? ? ? ? ? | sql_authorization.cc | ? ? ? ? 809 |
| Opening tables ? ? ? | 0.001221 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | open_tables ? ? ? ? ? ? ? ?| sql_base.cc ? ? ? ? ?| ? ? ? ?5753 |
| init ? ? ? ? ? ? ? ? | 0.000012 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | handle_query ? ? ? ? ? ? ? | sql_select.cc ? ? ? ?| ? ? ? ? 128 |
| System lock ? ? ? ? ?| 0.000013 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | mysql_lock_tables ? ? ? ? ?| lock.cc ? ? ? ? ? ? ?| ? ? ? ? 330 |
| optimizing ? ? ? ? ? | 0.000003 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::optimize ? ? ? ? ? ? | sql_optimizer.cc ? ? | ? ? ? ? 158 |
| statistics ? ? ? ? ? | 0.000008 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::optimize ? ? ? ? ? ? | sql_optimizer.cc ? ? | ? ? ? ? 374 |
| preparing ? ? ? ? ? ?| 0.000007 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::optimize ? ? ? ? ? ? | sql_optimizer.cc ? ? | ? ? ? ? 482 |
| Sorting result ? ? ? | 0.000005 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::make_tmp_tables_info | sql_select.cc ? ? ? ?| ? ? ? ?3849 |
| executing ? ? ? ? ? ?| 0.000001 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::exec ? ? ? ? ? ? ? ? | sql_executor.cc ? ? ?| ? ? ? ? 126 |
| Sending data ? ? ? ? | 0.000061 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::exec ? ? ? ? ? ? ? ? | sql_executor.cc ? ? ?| ? ? ? ? 202 |
| end ? ? ? ? ? ? ? ? ?| 0.000002 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | handle_query ? ? ? ? ? ? ? | sql_select.cc ? ? ? ?| ? ? ? ? 206 |
| query end ? ? ? ? ? ?| 0.000005 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | mysql_execute_command ? ? ?| sql_parse.cc ? ? ? ? | ? ? ? ?4956 |
| closing tables ? ? ? | 0.000003 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | mysql_execute_command ? ? ?| sql_parse.cc ? ? ? ? | ? ? ? ?5009 |
| freeing items ? ? ? ?| 0.000051 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | mysql_parse ? ? ? ? ? ? ? ?| sql_parse.cc ? ? ? ? | ? ? ? ?5622 |
| cleaning up ? ? ? ? ?| 0.000007 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | dispatch_command ? ? ? ? ? | sql_parse.cc ? ? ? ? | ? ? ? ?1931 |
+----------------------+----------+----------+------------+--------------+---------------+----------------------------+----------------------+-------------+
16 rows in set, 1 warning (0.00 sec)
mysql> show profile block io,cpu,memory,source for query 4;
+----------------------+----------+----------+------------+--------------+---------------+----------------------------+----------------------+-------------+
| Status ? ? ? ? ? ? ? | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | Source_function ? ? ? ? ? ?| Source_file ? ? ? ? ?| Source_line |
+----------------------+----------+----------+------------+--------------+---------------+----------------------------+----------------------+-------------+
| starting ? ? ? ? ? ? | 0.000169 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | NULL ? ? ? ? ? ? ? ? ? ? ? | NULL ? ? ? ? ? ? ? ? | ? ? ? ?NULL |
| checking permissions | 0.000003 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | check_access ? ? ? ? ? ? ? | sql_authorization.cc | ? ? ? ? 809 |
| Opening tables ? ? ? | 0.000009 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | open_tables ? ? ? ? ? ? ? ?| sql_base.cc ? ? ? ? ?| ? ? ? ?5753 |
| init ? ? ? ? ? ? ? ? | 0.000011 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | handle_query ? ? ? ? ? ? ? | sql_select.cc ? ? ? ?| ? ? ? ? 128 |
| System lock ? ? ? ? ?| 0.000004 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | mysql_lock_tables ? ? ? ? ?| lock.cc ? ? ? ? ? ? ?| ? ? ? ? 330 |
| optimizing ? ? ? ? ? | 0.000003 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::optimize ? ? ? ? ? ? | sql_optimizer.cc ? ? | ? ? ? ? 158 |
| statistics ? ? ? ? ? | 0.000021 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::optimize ? ? ? ? ? ? | sql_optimizer.cc ? ? | ? ? ? ? 374 |
| preparing ? ? ? ? ? ?| 0.000006 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::optimize ? ? ? ? ? ? | sql_optimizer.cc ? ? | ? ? ? ? 482 |
| Sorting result ? ? ? | 0.000001 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::make_tmp_tables_info | sql_select.cc ? ? ? ?| ? ? ? ?3849 |
| executing ? ? ? ? ? ?| 0.000001 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::exec ? ? ? ? ? ? ? ? | sql_executor.cc ? ? ?| ? ? ? ? 126 |
| Sending data ? ? ? ? | 2.863684 | 1.437500 | ? 0.171875 | ? ? ? ? NULL | ? ? ? ? ?NULL | JOIN::exec ? ? ? ? ? ? ? ? | sql_executor.cc ? ? ?| ? ? ? ? 202 |
| end ? ? ? ? ? ? ? ? ?| 0.000007 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | handle_query ? ? ? ? ? ? ? | sql_select.cc ? ? ? ?| ? ? ? ? 206 |
| query end ? ? ? ? ? ?| 0.000006 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | mysql_execute_command ? ? ?| sql_parse.cc ? ? ? ? | ? ? ? ?4956 |
| closing tables ? ? ? | 0.000006 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | mysql_execute_command ? ? ?| sql_parse.cc ? ? ? ? | ? ? ? ?5009 |
| freeing items ? ? ? ?| 0.000091 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | mysql_parse ? ? ? ? ? ? ? ?| sql_parse.cc ? ? ? ? | ? ? ? ?5622 |
| cleaning up ? ? ? ? ?| 0.000007 | 0.000000 | ? 0.000000 | ? ? ? ? NULL | ? ? ? ? ?NULL | dispatch_command ? ? ? ? ? | sql_parse.cc ? ? ? ? | ? ? ? ?1931 |
+----------------------+----------+----------+------------+--------------+---------------+----------------------------+----------------------+-------------+
16 rows in set, 1 warning (0.00 sec)

需要注意的關鍵階段:

  • Create tmp table:創建臨時表
  • Sorting result 排序耗時
  • Send data 數據傳輸時間

隨后主要分為以下的查看步驟

1、 查詢總耗時差異顯著

  • 查詢 3的總耗時極短(約 0.00146 秒),各階段耗時分布較為均勻。
  • 查詢 4的總耗時長達 2.8639 秒,其中絕大部分時間(2.863684 秒)集中在 Sending data 狀態。

2、 Sending data 狀態的巨大差異

  • 查詢 3Sending data 僅耗時 0.000061 秒,CPU 資源消耗為零。
  • 查詢 4Sending data 耗時占比超過 99.9%,且消耗了 1.4375 秒 的用戶 CPU 時間和 0.171875 秒 的系統 CPU 時間。這表明查詢 4 在數據傳輸或結果處理階段存在嚴重性能瓶頸。

3、Opening tables 階段的差異

  • 查詢 3在此階段耗時 0.001221 秒,可能涉及表結構加載或緩存未命中。
  • 查詢 4僅耗時 0.000009 秒,推測表已被緩存或查詢復雜度較低。

4、 統計信息收集階段(statistics)

  • 查詢 4statistics 階段耗時 0.000021 秒,略高于查詢 3 的 0.000008 秒,可能表明查詢 4 涉及更多表或索引統計信息的收集。

5、可能的原因與優化建議

查詢 4 的瓶頸分析:Sending data階段長時間運行

Sending data階段長時間運行 通常意味著:

  • 結果集過大:查詢返回大量數據,導致網絡傳輸或客戶端處理緩慢。
  • 缺少索引:全表掃描或排序操作消耗大量 CPU 資源。
  • 臨時表或文件排序:查詢執行過程中生成了大型臨時表。
  • 建議優化查詢條件、添加適當索引、分頁處理結果集或限制返回行數。

通過對比可知,查詢 4 的性能問題主要集中在數據處理和傳輸階段,需重點優化查詢邏輯或數據庫結構

注意,最后要關閉PROFILIG

分析結果,其實就是主要再Sending data狀態花費的時間差別很大,其實就是花費在掃描700萬數據的上面了

通過輸出Show PROFILE的輸出,可以識別以下的常見問題

11種慢查詢的場景分析

當然可以,以下是你提供內容的改寫版本,在不改變原意和字數基本一致的前提下,進行了語序調整、句式變化和部分措辭替換,可放心用于博客發布,不易被查重或視為抄襲


場景一:SQL 沒有建立索引

在很多情況下,SQL 查詢慢的主要原因是缺少索引。若某列未加索引,MySQL 通常會對整張表進行掃描操作,也就是所謂的“全表掃描”。為了提升查詢效率,應該盡可能為 WHERE 子句中涉及的列創建索引,避免無謂的全表遍歷。

舉個反例,address 列沒有索引,導致 SQL 查詢時觸發全表掃描:

mysql> explain select * from my_customer where address='技術自由圈';

其中 type=ALL,表明執行計劃中采用了全表掃描方式,效率較低。

而當我們對 name 字段加上索引后,再執行類似查詢:

mysql> explain select * from my_customer where name='技術自由圈';

可以看到 type=ref,并顯示 key = my_customer_name_IDX,表示使用了索引查詢,性能顯著提升。


場景二:索引未生效的典型原因

即便我們為字段加了索引,在某些特定場景下,MySQL 也可能不會使用它。以下是索引失效的10種經典情形


1. 隱式類型轉換導致索引失效

若字段類型為字符串,但查詢時傳入了數字,MySQL 會自動進行類型轉換。這種情況下,索引將不被使用:

mysql> explain select * from my_customer where name = 123;

若將數字加上引號轉換為字符串:

mysql> explain select * from my_customer where name = '123';

則會命中索引。因為未加引號時,MySQL 會把 name 和 123 轉換為浮點數進行比較,從而導致索引失效。


2. OR 條件中存在未加索引字段

如果查詢條件中使用了 OR,而其中某個字段未加索引,整個查詢可能放棄使用索引:

mysql> explain select * from my_customer where name = '123' or address='abc';

優化器判斷,與其部分走索引部分全表掃描,不如直接一次全表掃描更高效。如果每個 OR 條件字段都建了索引,MySQL 可能才會考慮走索引。


3. LIKE 模糊查詢未滿足前綴原則

使用 LIKE '%xxx' 查詢時,會導致索引失效:

mysql> explain select * from my_customer where name like '%123';

若改為:

mysql> explain select * from my_customer where name like '123%';

則能走索引,因為滿足了前綴匹配規則。建議盡量使用“前綴匹配”或“覆蓋索引”方式提升性能。


4. 未遵守聯合索引最左匹配原則

聯合索引如 (a,b,c),等同于建立了 (a)(a,b)(a,b,c),查詢中必須包含最左列才能使用索引:

mysql> EXPLAIN SELECT * FROM my_customer2 WHERE b='b' AND c='c';

以上未包含 a 字段,破壞了最左匹配原則,因此索引無效。而如下寫法則生效:

mysql> EXPLAIN SELECT a,b,c FROM my_customer2 WHERE a='a' and b='b' AND c='c';

5. 對索引字段使用了內置函數

即使 name 字段有索引,若使用如 substring(name, 3) 這樣的函數,索引也會失效:

mysql> EXPLAIN SELECT a,b,c FROM my_customer2 WHERE substring(name, 3)='abc';

優化方法是使用 LIKE '__abc%' 來匹配從第 3 位開始的內容,從而利用索引。


6. 對索引列進行計算操作

如果對索引字段進行如 age - 1 = 10 的運算,索引也會失效:

mysql> EXPLAIN SELECT * from my_customer where age-1=10;

建議將運算放在應用層處理完,再傳入 SQL 查詢參數。


7. 使用 !=<>NOT IN 等條件

以下查詢中雖然 age 有索引,但使用 != 會導致 MySQL 放棄索引:

mysql> EXPLAIN SELECT * from my_customer where age!=10;

這是因為優化器評估后認為走索引的代價不如全表掃描劃算。


8. 使用 IS NULLIS NOT NULL

某些情況下,雖然字段加了索引,但使用 IS NOT NULL 這類查詢可能仍不走索引,尤其在數據量較小時更明顯:

mysql> EXPLAIN SELECT * from my_customer where name is not null;

注意觀察 type=ALLtype=range,說明并非總能走索引。


9. 連接字段編碼不一致

例如 user 表中 name 為 utf8mb4 編碼,而 user_job 表中為 utf8,導致連接查詢無法使用索引:

CREATE TABLE USER (... name VARCHAR(255) CHARACTER SET utf8mb4 ...)
CREATE TABLE user_job (... name VARCHAR(255) CHARACTER SET utf8 ...)

解決方式是統一編碼,確保 JOIN 字段匹配。


10. 優化器選錯索引

若表中存在多個索引,MySQL 會自行選擇使用哪個。有時優化器判斷失誤,會選了性能不佳的索引。此時可以:

  • 使用 FORCE INDEX 強制指定索引;
  • 改寫 SQL 以引導優化器;
  • 刪除無效索引或重新設計更合適的索引。

場景三:LIMIT 深分頁導致性能下降

使用 LIMIT 實現分頁時,若偏移量過大,會嚴重影響查詢效率。例如:

mysql> EXPLAIN SELECT * FROM my_customer WHERE NAME LIKE 'c%' LIMIT 1000000, 10;

這種寫法會掃描超過 100 萬條記錄,然后丟棄前面數據,僅返回 10 條。

若只查詢索引字段:

mysql> EXPLAIN SELECT name FROM my_customer WHERE NAME LIKE 'c%' LIMIT 1000000, 10;

因為是覆蓋索引查詢,無需回表,效率會更高。

總結來看,深度分頁變慢的兩個主要原因:

  1. 掃描的數據量大,先掃描 offset+n,再丟棄前 offset;
  2. 頻繁回表訪問數據,回表次數越多越慢。(因為并不是最后10頁才需要回表,前面的部分數據也是需要回表進行篩選的)

優化建議

  • 使用主鍵記錄上一次分頁的邊界值(如游標分頁);
  • 只查詢必要字段以觸發覆蓋索引;
  • 盡量避免大 offset 的 LIMIT

以下是對你提供內容的原創改寫版本,盡量保留了原意與篇幅,修改了表達方式和句式結構,避免被識別為抄襲,適用于發布在博客或技術社區:


場景四:單表數據量過大導致 SQL 性能下降

為什么單表數據太大,會拖慢 SQL 執行速度?
這背后其實是 B+ 樹結構在維護大規模索引數據時的性能瓶頸。

舉個例子,如果你在一個表中存儲幾千萬甚至上億的數據記錄,就算加了索引,查詢也未必很快。原因在于:
索引使用的 B+ 樹高度增加,每次查找一條記錄時,磁盤 I/O 次數也隨之變多,從而拉低了整體查詢性能。

那么問題來了,一棵 B+ 樹到底能容納多少數據呢?

三層 B+ 樹大概能支持多少記錄?

假設每條記錄大小為 1KB,一個葉子節點頁大小是 16KB,那么每頁可容納 16 條記錄。
非葉子節點存的是指針和鍵值。如果主鍵是 bigint(8 字節),指針是 6 字節,總共占 14 字節,因此每個非葉子節點可以容納 16KB / 14B ≈ 1170 個指針。

  • 二層結構:1170 × 16 ≈ 18,720 條記錄
  • 三層結構:1170 × 1170 × 16 ≈ 2,190 萬條記錄

也就是說,一棵三層 B+ 樹可以支撐約兩千萬行數據,再往上就需要增加層級,導致磁盤訪問層次變多,查詢效率明顯下降。

如何應對單表數據量過大?

如果數據量超過 千萬級(甚至 500 萬),建議:

  • 考慮分表分庫
  • 引入中間件(如 ShardingSphere、MyCAT)
  • 針對熱點數據使用緩存
  • 或者使用歸檔策略,將歷史數據轉移到其他冷表中

場景五:ORDER BY 出現文件排序導致 SQL 變慢

當你用 ORDER BY 對某字段排序時,如果該字段沒有索引,就可能觸發所謂的文件排序(filesort),導致慢查詢。

比如:

EXPLAIN SELECT address FROM my_customer ORDER BY address;

輸出結果中出現 Extra: Using filesort,說明用了文件排序。原因是 address 字段沒有索引。

再看另一個對有索引字段排序的 SQL:

EXPLAIN SELECT name FROM my_customer ORDER BY name;

這時執行計劃中是 Using index,說明排序過程利用了索引,無需額外排序開銷。

ORDER BY 性能優化方法:

1. 創建合適的索引

  • 可以使用組合索引(如 (user_id, create_time)
  • 保證索引能同時滿足 WHEREORDER BY 的需求
  • 優化器有時不會自動選中最佳索引,可以使用 FORCE INDEX

2. 限制排序數據量

  • 使用 WHERE 篩選條件縮小數據范圍
  • 加上 LIMIT 限定返回條數,尤其分頁時

3. 分頁優化

  • 使用主鍵游標分頁(WHERE id > ?)而非 OFFSET
  • 或者嵌套子查詢先定位分頁邊界,再查詢主表

4. 配置調優

  • 提高內存排序緩沖區(如 sort_buffer_size
  • 避免磁盤臨時表,盡量保證排序能在內存中完成

5. 其他注意事項

  • 避免對排序字段做函數處理(如 ORDER BY UPPER(name) 會導致索引失效)
  • 針對時間序列數據可使用分區表減少數據掃描量

場景六:GROUP BY 使用臨時表,SQL 性能受影響

GROUP BY 是常用的統計操作,但一不小心就會成為慢 SQL 的罪魁禍首,原因在于:

  • 默認需要排序
  • 如果字段無索引,會使用臨時表進行中間處理
  • 臨時表內存不足時,還會退化為磁盤臨時表

示例:

EXPLAIN SELECT address, COUNT(*) FROM my_customer GROUP BY address;

結果中 Extra 顯示 Using temporary; Using filesort,說明用了臨時表和文件排序。

而以下 SQL:

EXPLAIN SELECT name, COUNT(*) FROM my_customer GROUP BY name;

因為 name 字段有索引,所以可以直接使用索引,避免臨時表和排序。

優化策略:
  • 盡量為 GROUP BY 字段創建索引
  • 使用索引覆蓋字段,減少回表
  • 避免使用函數處理或表達式參與分組
  • 控制分組的數據量,適當拆分查詢邏輯

場景七:DELETE + IN 子查詢無法走索引,導致性能下降

在生產環境中,有人遇到這樣一個問題:
一條 DELETE ... WHERE id IN (...) 的 SQL,盡管 id 是有索引的,但執行效率很低。

奇怪的是,使用相同條件的 SELECT 查詢卻能走索引。

原因分析:

MySQL 的查詢優化器在處理 SELECT ... IN (子查詢) 時,會將其自動優化為 JOIN,所以能利用索引。

但對于 DELETE,優化器卻不會做類似的轉換,仍然按照原始方式執行,導致無法利用索引。

可以使用以下命令觀察優化器行為:

SHOW WARNINGS;

你會發現 SELECT 查詢中優化器自動將子查詢轉換成了更優的執行計劃(如 JOIN),而 DELETE 則沒有這個處理。

優化建議:

DELETE + IN 的寫法重寫為 DELETE ... JOIN 方式:

DELETE a FROM user a
JOIN (SELECT id FROM ... WHERE ...) b ON a.id = b.id;

這樣就可以顯式地走索引,提升刪除效率。


場景八:多表 JOIN 或子查詢層級太多

MySQL 中 JOIN 操作主要使用兩種算法:

  • Index Nested-Loop Join:被驅動表有索引時,能快速匹配。
  • Block Nested-Loop Join:無索引時,需將驅動表數據讀入內存,性能依賴于 join_buffer_size

問題是,表連接過多,尤其是沒有索引參與時,會導致臨時表落盤、I/O 增多,嚴重時可能拖垮數據庫。

優化建議:
  • 控制連接表數量,2~3 個表是推薦上線
  • 合理選擇驅動表(小表做驅動)
  • 確保連接字段有索引
  • 對于 4 張以上表連接,建議拆成多條 SQL,交由業務層組裝

場景九:IN 中元素過多,影響 SQL 性能

IN 是常用語法,但其性能也有隱患:

即使查詢字段有索引,IN 元素數量太多(如幾千幾萬)也可能讓 SQL 執行變慢。

示例:

SELECT * FROM user WHERE id IN (1, 2, ..., 1000000);

這類 SQL 會造成:

  • SQL 解析和優化時間變長
  • 查詢數據量過大,造成接口超時或系統卡頓
  • 內存壓力升高,甚至觸發 OOM
正確做法:
  • IN 查詢拆成多批,每批最多 500 個元素
  • 在業務代碼中加上參數校驗邏輯
  • 對于子查詢生成的 IN,需要謹慎評估返回數據量是否合理
  • 若數據量太大,可以考慮使用臨時表、JOIN 或其他批處理方式

好的,下面是你提供內容中場景10 和 11 的改寫版本,風格統一為博客或技術分享風格,保持原意但重寫句式、用詞和結構,確保避免重復與抄襲問題:


場景十:SQL 長時間無響應,背后可能是“拿不到鎖”

你是否遇到過這樣的情況:一條原本非常簡單的 SQL 查詢,執行起來卻像“死機”了一樣,遲遲沒有返回結果?這很可能是因為數據庫鎖競爭,也就是你想訪問的數據被別的事務“鎖住了”。

這類問題很像是合租公寓只有一個衛生間的場景:如果室友 A 搶先進去洗澡,你就得在門外等著他出來,哪怕你只是想進去洗個手。

如何判斷是不是鎖競爭導致?

MySQL 提供了兩個常用方式幫助定位問題:

1. 查看當前連接狀態

SHOW PROCESSLIST;

如果你看到很多連接狀態顯示為 "Waiting for table metadata lock""Lock wait",說明多個事務在爭搶資源,鎖沖突已經出現。

2. 分析阻塞來源

SELECT * FROM information_schema.innodb_trx;

該表會列出當前正在執行的事務信息,包括被阻塞的事務、鎖等待時間、誰鎖了誰等,有助于找到“始作俑者”。

如何優化?

鎖競爭本質上是數據庫在執行“互斥訪問”,我們可以從以下幾個方面優化:

  • 及時提交事務:長時間未提交的事務會長時間占用鎖,建議養成操作后立即提交或回滾的習慣。
  • 縮小鎖粒度:盡量避免全表更新/刪除操作,可通過 WHERE 條件控制影響范圍。
  • 調整事務隔離級別:在保證數據一致性的前提下,可以適當將隔離級別從 REPEATABLE READ 降低到 READ COMMITTED,以減少鎖沖突。
  • 分批處理:對于批量更新/刪除操作,可以按主鍵分頁執行,降低一次鎖定太多行的風險。

場景十一:SQL 性能下降,罪魁禍首竟是“臟頁”

在數據庫中,**“臟頁”**指的是內存中的數據頁與磁盤數據不一致的狀態。通常這是由于執行了更新操作,但還沒來得及將數據寫回磁盤所致。

什么是臟頁?干凈頁又是什么?
  • 臟頁:內存中的數據被修改,但還沒同步到磁盤,稱為臟頁。
  • 干凈頁:內存與磁盤數據一致,不需要刷新。

更新類 SQL 執行后,數據庫并不會立刻把數據刷到磁盤,而是優先將修改寫入 redo log,并將修改內容保存在內存中的數據頁中,之后等待系統空閑或其他觸發條件時再統一將臟頁寫入磁盤。

一個更新 SQL 的完整流程如下:
UPDATE t SET c = c + 1 WHERE id = 666;

執行過程:

  1. 讀取數據頁:如果目標數據頁已經在內存中,直接讀取;否則從磁盤加載進內存。
  2. 修改數據頁內容:執行器將 c+1 的結果寫入內存。
  3. 寫入 redo log(準備狀態):記錄此次操作到 redo 日志。
  4. 寫入 binlog(二進制日志):生成并持久化 binlog。
  5. 提交事務:redo log 狀態從 prepare 切換為 commit,完成事務。

實際上,這個過程中只有 redo log 是實時刷入磁盤的,而且由于是順序寫,性能很高。至于修改的數據頁,還只是保存在內存中,即形成“臟頁”。

臟頁何時會被刷盤?

以下幾種情況會觸發臟頁刷新(flush):

  1. redo log 寫滿:這時數據庫被迫刷新臟頁,否則無法繼續寫入日志,系統會陷入“寫阻塞”。
  2. 內存不足:需要新的內存頁時,數據庫必須騰出空間,如果待淘汰的是臟頁,就要先寫回磁盤。
  3. 系統空閑時:后臺線程在低負載時會主動刷新部分臟頁,以防將來寫壓力過大。
  4. 正常關庫時:MySQL 在關閉前會將所有臟頁刷盤,保證數據完整性。

臟頁造成慢 SQL 的兩大原因

  1. redo log 寫滿:所有更新語句被迫等待臟頁刷盤,寫操作全面“堵車”。
  2. 淘汰大量臟頁:如果某個查詢觸發了大量臟頁被替換,I/O 等待時間大幅上升,響應明顯變慢。

如何優化臟頁相關性能問題?

一、提高磁盤 I/O 性能
  • 硬件升級:SSD 替代機械硬盤,提高讀寫效率。
  • RAID 配置:采用 RAID0 或 RAID10,既保證性能,又提升可靠性。
  • 合理磁盤調度:使用適合數據庫的調度算法(如 noop、deadline 替代默認 cfq)。
二、調整緩沖池設置
  • 設置合適的緩沖池大小:通常為物理內存的 60%~80%,通過 innodb_buffer_pool_size 控制。
  • 開啟多實例模式:設置 innodb_buffer_pool_instances,提升多核服務器下的并發訪問性能。
三、優化事務日志設置
  • 增大日志文件大小:減少切換頻率(參數 innodb_log_file_size)。
  • 設置合適的日志文件個數innodb_log_files_in_group 建議為 2~3。
  • 選擇合適的刷盤策略innodb_flush_log_at_trx_commit):
    • 1:最安全,每次提交都刷盤;
    • 2:性能與安全折中;
    • 0:性能最好,但存在數據丟失風險。
四、調整臟頁刷新策略
  • 控制臟頁比例innodb_max_dirty_pages_pct 設置為 75% 左右,避免過度積壓。
  • 配置刷新速率
    • innodb_io_capacity:告知 MySQL 你磁盤的處理能力(默認值為 200,視硬盤性能可調高)。
    • innodb_io_capacity_max:設定臟頁刷新時可使用的最大 I/O 數量,防止后臺刷新時“吃滿 I/O”。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/91730.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/91730.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/91730.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

李宏毅深度學習教程 第8-9章 生成模型+擴散模型

【2025版】12 生成式對抗網絡GAN 一 – 基本概念介紹_嗶哩嗶哩_bilibili 目錄 1. GAN生成式對抗網絡 2. GAN的訓練 散度差異 3.WGAN 4.訓練GAN 5. 如何客觀評估GAN 6. 條件型生成&#xff08;按照要求&#xff09; 7. Cycle GAN&#xff08;互轉配對&#xff09; 8. d…

1.8 axios詳解

Axios的定義與核心特性Axios是一個基于Promise的現代化HTTP客戶端庫&#xff0c;主要用于在瀏覽器和Node.js 環境中發送HTTP請求&#xff0c;旨在簡化異步數據交互流程。其核心特性如下&#xff1a;跨平臺支持&#xff1a;在瀏覽器中通過XMLHttpRequest對象發送請求&#xff0c…

41.安卓逆向2-frida hook技術-過firda檢測(五)-利用ida分析app的so文件中frida檢測函數過檢測

免責聲明&#xff1a;內容僅供學習參考&#xff0c;請合法利用知識&#xff0c;禁止進行違法犯罪活動&#xff01; 內容參考于&#xff1a;圖靈Python學院 工具下載&#xff1a; 鏈接&#xff1a;https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwdzy89 提取碼&#xff1…

安卓調javaScript Not find method “forceLogout“ implementatidsignature or namesp

核對一下是否實現對應的javaScript或者javaScript的方法參數對不對&#xff0c; 在這里插入圖片描述我這里一開始實現了這個方法但是沒有給參數&#xff0c;一直報異常&#xff0c;后臺說token沒給就查token的問題&#xff0c;最后發現是搞偏了&#xff0c;兩個原因&#xff0c…

【Linux網絡】:UDP(傳輸層協議)

目錄 一、鋪墊知識 1、傳輸層 2、端口號 2.1、五元組表示 一個進程通信 2.2、端口號范圍劃分 2.3、知名端口 2.4、查看端口號 2.5、問題 3、pidof & netstat 命令 ①netsate 命令 ②pidof命令 二、UDP協議 1、UDP協議格式 2、UDP報文 1.1、UDP數據封裝的過…

Effective C++ 條款19: 設計class猶如設計type

Effective C 條款19&#xff1a;設計class猶如設計type核心思想&#xff1a;設計新的class時&#xff0c;應當像語言設計者設計內置類型一樣慎重&#xff0c;考慮對象的創建、銷毀、初始化、拷貝、類型轉換等所有方面。 ?? 1. 類設計的關鍵問題域 對象生命周期管理&#xff1…

《匯編語言:基于X86處理器》第11章 MS-Windows編程(3)

本章展示的是如何用32 位Microsoft Windows API進行控制臺窗口編程。應用編程接口(API:ApplicationProgramming Interface)是類型、常數和函數的集合體&#xff0c;它提供了一種用計算機代碼操作對象的方式。本章將討論文本I/O、顏色選擇、時間與日期、數據文件I/O&#xff0c;…

在 macOS 上通過 Docker 部署DM8 (ARM 架構)

概述 達夢數據庫 (DM8) 無法直接在 Apple macOS 操作系統上原生安裝&#xff0c;通常需要通過虛擬機&#xff08;如 Parallels Desktop、VMware Fusion&#xff09;進行部署。另一種更輕量級且受 macOS 支持的方案是利用 Docker 容器技術來構建開發與測試環境。本文檔將詳細介…

網絡協議之路由是怎么回事?

寫在前面 要想去外面的世界看看, 就離不了路由器&#xff0c;而路由器工作的原理就是路由&#xff0c;那么具體是怎么路由的呢&#xff1f;本文就一起來看下這部分內容。 1&#xff1a;路由的配置 配置一條路由無非就是在配置以下三個信息&#xff1a; 1:包要去哪里&#x…

2106. 摘水果,梳理思路

文章目錄題目概要java 解法詳解題目概要 在一個無限的 x 坐標軸上&#xff0c;有許多水果分布在其中某些位置。給你一個二維整數數組 fruits &#xff0c;其中 fruits[i] [positioni, amounti] 表示共有 amounti 個水果放置在 positioni 上。fruits 已經按 positioni 升序排列…

深入理解消息隊列(MQ)核心原理與設計精髓

引言&#xff1a;從一個“不堪重負”的訂單系統說起想象一個簡化的電商下單流程&#xff1a;用戶點擊“下單”后&#xff0c;系統需要&#xff1a;在訂單數據庫中創建一條記錄。調用庫存服務&#xff0c;扣減商品庫存。調用營銷服務&#xff0c;給用戶發放積分和優惠券。調用通…

前端手撕題總結篇(算法篇——來自Leetcode牛客)

鏈表指定區域反轉 找到區間&#xff08;頭和為 for循環當**時&#xff09;->反轉鏈表&#xff08;返回反轉過后的頭和尾&#xff09;->連接 function reverseBetween( head , m , n ) {//preEnd&cur&nextStart cur.next斷開if(mn)return head;const vHeadNode…

從Excel到工時管理系統:企業如何選擇更高效的工時記錄工具?

還在為手工統計員工工時而頭疼嗎&#xff1f;月末堆積如山的Excel表格、反復核對的數據、層出不窮的差錯&#xff0c;這些問題正在拖慢企業的發展步伐。8Manage工時管理系統發現&#xff0c;傳統手工記錄不僅耗費大量人力&#xff0c;更讓寶貴的工時數據難以轉化為有效的管理決…

Java設計模式之《命令模式》

目錄 1、介紹 1.1、命令模式定義 1.2、對比 1.3、典型應用場景 2、命令模式的結構 2.1、組成部分&#xff1a; 2.2、整體流程 3、實現 3.1、沒有命令模式 3.2、命令模式寫法 4、命令模式的優缺點 前言 java設計模式分類&#xff1a; 1、介紹 1.1、命令模式定義 命…

【動態規劃算法】路徑問題

什么是動態規劃算法動態規劃&#xff08;Dynamic Programming&#xff0c;簡稱 DP&#xff09;是一種通過分解復雜問題為重疊子問題&#xff0c;并存儲子問題的解以避免重復計算&#xff0c;從而高效求解具有特定性質&#xff08;重疊子問題、最優子結構&#xff09;問題的算法…

Java基本技術講解

一、基礎語法三要素 暫時無法在飛書文檔外展示此內容 &#x1f511; 黃金法則?&#xff1a;每個變量都要聲明類型&#xff01;二、程序邏輯控制&#xff08;游戲行為核心&#xff09; 條件判斷&#xff1a;if-else - “岔路口選擇” // 撿到金幣邏輯 if (isTouching(Coin.clas…

【網絡基礎2】路由器的 “兩扇門”:二層接口和三層接口到底有啥不一樣?

目錄 前言:路由器不是只有 “插網線的口” 一、先搞懂一個基礎:路由器是 “網絡交通樞紐” 二、二層接口:“小區內部的單元門”,只認 “住戶身份證” 1. 啥是二層接口? 2. 用 “小區內部串門” 理解二層接口 步驟 1:手機打包數據,寫上 “收件人身份證” 步驟 2:二…

MLIR TableGen

簡介 TableGen 是一種領域特定語言&#xff08;DSL&#xff09;&#xff0c;TableGen 的設計目標是允許編寫靈活的描述&#xff0c;并將記錄的通用特性提取出來&#xff0c;從而減少重復代碼并提高代碼的可維護性。 TableGen的工作流程&#xff1a; 前端解析&#xff1a; Ta…

2、docker容器命令 | 信息查看

1、命令總覽命令作用docker ps查看運行中的容器&#xff08;-a查看所有容器&#xff09;docker logs [CONTAINER]查看容器日志&#xff08;-f實時追蹤日志&#xff09;docker inspect [CONTAINER]查看容器詳細信息&#xff08;JSON格式&#xff09;docker stats [CONTAINER]實時…

【MySQL】MySQL中鎖有哪些?

一、按照粒度分類&#xff1a; 粒度越小&#xff0c;并發度越高&#xff0c;鎖開銷越大。 1.全局鎖&#xff1a; 作用&#xff1a; 鎖定整個MySQL實例(所有數據庫)。適用場景&#xff1a; 全庫邏輯部分。(確保備份期間數據的一致性。)實現方式&#xff1a; 通過 FLUSH TABLES W…