MySQL中的derived table(r12筆記第47天)
初始MySQL中的derived table還是在一個偶然的問題場景中。
下面的語句在執行的時候丟擲了錯誤。
UPDATE payment_data rr
SET rr.penalty_date = '2017-4-12'
where rr.id =
(SELECT min(r.id)
FROM payment_data r
where data_no =
(SELECT data_no
FROM user_debt
WHERE out_trade_no = 'bestpay_order_no1491812746329'));
ERROR 1093 (HY000): You can't specify target table 'rr' for update in FROM clause 如果對MySQL查詢最佳化器足夠了解就會明白,其實這種方式是MySQL不支援的,有沒有WA呢,還是有的,那就是透過一種特殊的子查詢來完成,也就是derived table
所以上面的語句使用如下的方式就可以破解。
UPDATE payment_data rr
SET rr.penalty_date = '2017-4-12'
where rr.id =
(SELECT min(t.id)
FROM (select id,data_no from payment_data r) t
where t.data_no =
(SELECT data_no
FROM user_debt
WHERE out_trade_no = 'bestpay_order_no1491812746329'));
我們回到剛剛提到的Derived table,在官方文件中是這麼說的。
Derived tables is the internal name for subqueries in the FROM clause.為了充分說明derived table,我還是舉例倒黴的t_fund_info這個表。
首先檢視兩條資料,作為我們測試的基礎資料,其中id是主鍵列.
> select id from t_fund_info limit 1,2;
+---------+
| id |
+---------+
| 138031 |
| 1754906 |
+---------+如果按照id列來查詢,就會發現效率極高。
> select * from t_fund_info where id=138031;
。。。
1 row in set (0.01 sec) 我們如果檢視執行計劃,就會發現是primary key的掃描方式。
> explain select * from t_fund_info where id=138031;
+----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | t_fund_info | const | PRIMARY | PRIMARY | 8 | const | 1 | |
+----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+
1 row in set (0.01 sec)那麼我們繼續換一種思路,使用兩種不同的derived table
第一種:
> select * from (select id from t_fund_info) t where t.id=138031;
1 row in set (1.12 sec)這個時候檢視執行計劃,就會看到derived table的字樣。
> explain select * from (select id from t_fund_info) t where t.id=138031;
+----+-------------+-------------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+-------+---------------+---------+---------+------+---------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 1998067 | Using where |
| 2 | DERIVED | t_fund_info | index | NULL | account | 182 | NULL | 2127101 | Using index |
+----+-------------+-------------+-------+---------------+---------+---------+------+---------+-------------+
2 rows in set (0.90 sec)看起來是1秒的執行速度,差別還不是很大,我們換第二種方式。
> select * from (select * from t_fund_info) t where t.id=138031;
ERROR 126 (HY000): Incorrect key file for table '/tmp/#sql_3e34_0.MYI'; try to repair it
這個時候就會發現這麼一個看似簡單的查詢竟然丟擲了錯誤。
檢視錯誤裡的資訊,是一個MYI的檔案,顯然是使用了臨時表的方式,典型的一個myisam表。
為了驗證這個過程,我儘可能完整的收集了/tmp目錄下的檔案使用情況,可以看到,佔用了2G多的空間,最後發現磁碟空間不足退出。
# df -h|grep \/tmp
/dev/shm 6.0G 4.1G 1.6G 73% /tmp
/dev/shm 6.0G 4.5G 1.2G 79% /tmp
/dev/shm 6.0G 4.8G 903M 85% /tmp
/dev/shm 6.0G 4.9G 739M 88% /tmp
/dev/shm 6.0G 5.0G 625M 90% /tmp
/dev/shm 6.0G 5.2G 498M 92% /tmp
/dev/shm 6.0G 5.3G 386M 94% /tmp
/dev/shm 6.0G 5.4G 250M 96% /tmp
/dev/shm 6.0G 5.5G 110M 99% /tmp
/dev/shm 6.0G 5.7G 4.0K 100% /tmp
/dev/shm 6.0G 3.7G 2.0G 66% /tmp
/dev/shm 6.0G 3.7G 2.0G 66% /tmp這裡有另外一個疑問,那就是這個表t_fund_info是個InnoDB表,佔用空間是400M左右,但是derived table使用率竟然達到了2G以上,不知道MySQL內部是怎麼進一步處理的。
-rw-rw---- 1 mysql mysql 9545 Oct 20 2016 t_fund_info.frm
-rw-rw---- 1 mysql mysql 482344960 Oct 20 2016 t_fund_info.ibd明顯可以看出這種方式還是有潛在的效能問題,難道myisam表佔有的空間更大,顯然不是,我測試了同樣資料量的myisam表,空間大概是270M左右。
那這種方式還有沒有改進的空間呢。我們試試檢視表達的是一個意思。
> create view test_view as select * from t_fund_info;
Query OK, 0 rows affected (0.00 sec)
> select *from test_view where id=138031;
。。。
1 row in set (0.01 sec)
執行計劃和主鍵的執行計劃一模一樣。
所以對於derived table的改進方式,一種是透過view來改進,另外一種則是儘可能避免使用。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-2138145/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL中的binlog和redo淺析(r12筆記第5天)MySql筆記
- MySQL原始碼安裝總結(r12筆記第12天)MySql原始碼筆記
- MySQL自增列的重複值問題(r12筆記第25天)MySql筆記
- MySQL無法建立表的問題分析(r12筆記第73天)MySql筆記
- MySQL中的批量初始化資料的對比測試(r12筆記第71天)MySql筆記
- MySQL傳輸表空間小結(r12筆記第2天)MySql筆記
- MySQL service啟動指令碼淺析(r12筆記第59天)MySql指令碼筆記
- MySQL 8.0 Reference Manual(讀書筆記51節--Optimizing Subqueries, Derived Tables, View References, and Common Table Expressions(1))MySql筆記ViewExpress
- MySQL 8.0 Reference Manual(讀書筆記52節--Optimizing Subqueries, Derived Tables, View References, and Common Table Expressions(2))MySql筆記ViewExpress
- MySQL數值型別在binlog中需要注意的細節(r12筆記第69天)MySql型別筆記
- 歸零的心態(r12筆記第82天)筆記
- mysqlpump的效能測試(r12筆記第89天)MySql筆記
- 相同update語句在MySQL,Oracle的不同表現(r12筆記第30天)MySqlOracle筆記
- 心理學中的效應簡單解讀(r12筆記第24天)筆記
- 使用pt工具檢測MySQL主從延遲(r12筆記第7天)MySql筆記
- 在eclipse中配置MySQL原始碼環境(r12筆記第14天)EclipseMySql原始碼筆記
- 分分鐘搭建MySQL一主多從環境(r12筆記第31天)MySql筆記
- 我爸爸眼中的我(r12筆記第22天)筆記
- 一個IT人和ppt的故事(r12筆記第39天)筆記
- 我的女兒二三事(七)(r12筆記第58天)筆記
- 玩足彩的一點感受(r12筆記第80天)筆記
- 分分鐘搭建MySQL Group Replication測試環境(二)(r12筆記第41天)MySql筆記
- MySQL自增列主從不一致的測試(r12筆記第37天)MySql筆記
- mysqldump的一點使用總結(r12筆記第81天)MySql筆記
- 駕考的一點總結(r12筆記第93天)筆記
- 推薦最近收藏的幾篇文章(r12筆記第85天)筆記
- mysqlpump和mysqldump的效能大比拼(r12筆記第90天)MySql筆記
- MySQL中的undo截斷(r11筆記第89天)MySql筆記
- 關於金錢的幾個小故事(r12筆記第8天)筆記
- 一種Oracle快速的整合遷移方案(r12筆記第98天)Oracle筆記
- Oracle閃回原理測試(三)(r12筆記第16天)Oracle筆記
- sandbox和MHA快速測試(r12筆記第32天)筆記
- Oracle 12c DBCA淺析(r12筆記第48天)Oracle筆記
- MySQL主從不一致發現的細小問題分析(r12筆記第63天)MySql筆記
- MySQL中的半同步複製(r11筆記第65天)MySql筆記
- MYSQL錯誤程式碼:1248 Every derived table must have its own alias 解決MySql
- 一個ORA-00600問題的簡單分析(r12筆記第18天)筆記
- 資料架構難點-資料分佈(r12筆記第43天)架構筆記