在某些數據訪問層框架中,會使用show full tables from test like 'demo',來檢查數據庫的狀態。當數據庫中表的數量較少時,並沒有出現嚴重的問題。但是當數據庫中的表數量多余千個時,且並發數較高時,通過show processlist就會發現show full tables語句絕大部分處於checking permissions狀態
| 2 | test | 192.168.15.128:57656 | NULL | Query | 0 | checking permissions | show full tables from test like '%demo%' |
| 3 | test | 192.168.15.128:57657 | NULL | Query | 0 | checking permissions | show full tables from test like '%demo%' |
| 4 | test | 192.168.15.128:57658 | NULL | Sleep | 0 | | NULL |
| 5 | test | 192.168.15.128:57659 | NULL | Query | 0 | Sending to client | show full tables from test like '%demo%' |
| 6 | test | 192.168.15.128:57662 | NULL | Query | 0 | checking permissions | show full tables from test like '%demo%' |
| 7 | test | 192.168.15.128:57661 | NULL | Query | 0 | checking permissions | show full tables from test like '%demo%' |
| 8 | test | 192.168.15.128:57660 | NULL | Query | 0 | checking permissions | show full tables from test like '%demo%' |
| 9 | test | 192.168.15.128:57663 | NULL | Query | 0 | checking permissions | show full tables from test like '%demo%' |
| 10 | test | 192.168.15.128:57664 | NULL | Query | 0 | checking permissions | show full tables from test like '%demo%' |
| 11 | test | 192.168.15.128:57665 | NULL | Query | 0 | checking permissions | show full tables from test like '%demo%' |
| 12 | test | 192.168.15.128:57666 | test | Query | 0 | starting | show processlist |
從給出的狀態信息來看,很多人會誤以為這是在該SQL需要做復雜的權限檢查。google一下之后,發現也有人遇到類似的問題,並認為是mysql.user表中的條目數過多。但是我本機中,顯然不是這個原因。
mysql> select count(*) from mysql.user;
+----------+
| count(*) |
+----------+
| 5 |
+----------+
1 row in set (0.00 sec)
由於show full tables from test like '%demo%'需要檢查test數據庫下的所有frm文件,因此表的數量越多,就越有可能出現這個問題。為了驗證,我在兩個實例上分別創建一個表和創建2000個表
一個表時,
mysql> set profiling=1;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> show full tables from test like 'demo';
+-----------------------+------------+
| Tables_in_test (demo) | Table_type |
+-----------------------+------------+
| demo | BASE TABLE |
+-----------------------+------------+
1 row in set (0.00 sec)
mysql> show profile;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000227 |
| checking permissions | 0.000020 |
| checking permissions | 0.000023 |
| Opening tables | 0.000452 |
| init | 0.000078 |
| System lock | 0.000051 |
| optimizing | 0.000030 |
| statistics | 0.000179 |
| preparing | 0.000134 |
| executing | 0.000069 |
| checking permissions | 0.000557 |
| Sending data | 0.000136 |
| end | 0.000036 |
| query end | 0.000032 |
| closing tables | 0.000042 |
| removing tmp table | 0.000110 |
| closing tables | 0.000060 |
| freeing items | 0.000122 |
| cleaning up | 0.000028 |
+----------------------+----------+
19 rows in set, 1 warning (0.01 sec)
2000個表時
mysql> set profiling=1;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> show full tables from test like 'demo';
+-----------------------+------------+
| Tables_in_test (demo) | Table_type |
+-----------------------+------------+
| demo | BASE TABLE |
+-----------------------+------------+
1 row in set (0.01 sec)
mysql> show profile;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000083 |
| checking permissions | 0.000004 |
| checking permissions | 0.000002 |
| Opening tables | 0.000032 |
| init | 0.000008 |
| System lock | 0.000005 |
| optimizing | 0.000003 |
| statistics | 0.000104 |
| preparing | 0.000024 |
| executing | 0.000004 |
| checking permissions | 0.002991 |
| Sending data | 0.000014 |
| end | 0.000003 |
| query end | 0.000005 |
| closing tables | 0.000002 |
| removing tmp table | 0.000003 |
| closing tables | 0.000002 |
| freeing items | 0.000047 |
| cleaning up | 0.000013 |
+----------------------+----------+
19 rows in set, 1 warning (0.01 sec)
0.002991/0.000557=5.36,其所消耗時間增長了5倍以上,在高並發下,其現象更明顯。
那么標注為紅色的checking permission是否真正表示在做權限檢查了,答案是否定的。
通過檢查MySQL5.6源碼,可以發現,在執行show full tables from test like '%demo%'時,checking permission期間其實做了兩部分工作,
1、檢查權限
2、遍歷test數據庫下所有的frm文件,並獲取相關信息。根據獲得的信息,經過like條件過濾后,寫入到一個臨時表(memory引擎表)中
在sending data階段,從這個臨時表,把數據發送給用戶
因此在某些SQL語句下,狀態為checking permission時,並不一定真的在做權限檢查。
所以不要頻繁的向數據庫發送show full tables from test like '%demo%',尤其是在表的數量很多時。