Mysql

調查慢查詢的工具/方法

  • December 26, 2019

我有一個帶有子查詢的查詢,兩者都很快,但是當它們結合起來時,它們需要永遠(意味著任何時間超過我的應用程序可接受的時間)。我嘗試使用“解釋”來查看發生了什麼,但對我沒有多大幫助。還有哪些其他方法可以調查慢查詢?

以下是我的問題的具體細節。我有一個產品列表,我想找到每個產品的第一個供應商活動的日期。如果我得到事件 ID 列表,查詢會很快(每個產品可能有多個事件,它們是按時間順序創建的,所以最小事件 ID 是最早的;ProdID 被索引);然後我使用這個事件 ID 列表來獲取日期,第二個查詢也很快(事件 ID 是主鍵,因此被索引)。但是,如果我將第一個查詢用作第二個查詢的子查詢,則需要永遠。

查詢一:

mysql> select min(VendorEventID) from Vendor_Events where ProdID in (598446938, 598446984, 598447024, 598447054, 598447311, 598447523, 598447764, 598447778, 
598448000, 598448048) and vendorid = 12 group by ProdID ;
+--------------------+
| min(VendorEventID) |
+--------------------+
|        11217790121 |
|        11217792453 |
|        11217793912 |
|        11217793894 |
|        11217794825 |
|        11217815018 |
|        11217813148 |
|        11217828936 |
|        11217830215 |
|        11217829202 |
+--------------------+
10 rows in set (0.00 sec)

查詢 2:

mysql> select * from Vendor_Events where VendorEventID in ( 11217790121, 11217792453, 11217793912, 11217793894, 11217794825, 11217815018, 11217813148, 11217828936, 11217830215, 11217829202 ) ;
+---------------+----------+-----------+---------------------+------------+--------+
| VendorEventID | VendorID | ProdID    | LoggedDate          | VendorType | NameID |
+---------------+----------+-----------+---------------------+------------+--------+
|   11217790121 |       12 | 598446938 | 2016-12-07 16:33:58 |          2 |     32 |
|   11217792453 |       12 | 598446984 | 2016-12-07 16:34:14 |          2 |     32 |
|   11217793894 |       12 | 598447054 | 2016-12-07 16:34:29 |          2 |     32 |
|   11217793912 |       12 | 598447024 | 2016-12-07 16:34:29 |          2 |     32 |
|   11217794825 |       12 | 598447311 | 2016-12-07 16:34:33 |          2 |     32 |
|   11217813148 |       12 | 598447764 | 2016-12-07 16:37:10 |          2 |     32 |
|   11217815018 |       12 | 598447523 | 2016-12-07 16:37:24 |          2 |     32 |
|   11217828936 |       12 | 598447778 | 2016-12-07 16:39:54 |          2 |     32 |
|   11217829202 |       12 | 598448048 | 2016-12-07 16:39:55 |          2 |     32 |
|   11217830215 |       12 | 598448000 | 2016-12-07 16:40:04 |          2 |     32 |
+---------------+----------+-----------+---------------------+------------+--------+
10 rows in set (0.04 sec)

把它們結合起來解釋:

mysql> explain  select * from Vendor_Events where VendorEventID in ( select min(VendorEventID) from Vendor_Events where ProdID in (598446938, 598446984, 598447024, 598447054, 598447311, 598447523, 598447764, 598447778, 598448000, 598448048) and vendorid = 12 group by ProdID ) ;
+----+--------------------+---------------+-------+-----------------+----------+---------+------+----------+--------------------------+
| id | select_type        | table         | type  | possible_keys   | key      | key_len | ref  | rows     | Extra                    |
+----+--------------------+---------------+-------+-----------------+----------+---------+------+----------+--------------------------+
|  1 | PRIMARY            | Vendor_Events | ALL   | NULL            | NULL     | NULL    | NULL | 78536406 | Using where              |
|  2 | DEPENDENT SUBQUERY | Vendor_Events | range | ProdID,ProdID_2 | ProdID_2 | 16      | NULL |       15 | Using where; Using index |
+----+--------------------+---------------+-------+-----------------+----------+---------+------+----------+--------------------------+
2 rows in set (0.00 sec)

當然,如果有人可以幫助我找出導致查詢超慢的原因,我將不勝感激。但是如果人們想告訴我還有什麼其他方法可以調查慢查詢,我也很喜歡,因為我們都會時不時地遇到慢查詢。;-)

為什麼查詢很慢:

explain的輸出顯示如下:

該查詢將掃描第一個表 78536406 中的所有行,並且對於這些行中的每一行,它將從第二個表中掃描平均 15 行。總共將讀取 (78536406*15) 行。這本身就是一個緩慢的指標。

考慮到表的大小,可能會有一些記憶體交換,這也會導致緩慢(從磁碟讀取到 RAM,重複。)

如何改進此查詢:

一種可能的方法是從子查詢中創建一個表,並在第一個表和上一步中的表之間使用 INNER JOIN。

CREATE TABLE tmp_ve as select min(VendorEventID) as VendorEventID from Vendor_Events where ProdID in (598446938, 598446984, 598447024, 598447054, 598447311, 598447523, 598447764, 598447778, 598448000, 598448048) and vendorid = 12 group by ProdID;
-- No need to add indexes to this table, as it would contain only 10 rows.
SELECT Vendor_Events.* FROM Vendor_Events INNER JOIN tmp_ve USING (VendorEventID);

我沒有嘗試過,但是如果您explain進行第二次查詢,它將從tmp_ve表開始,然後對於每個值,它將使用索引Vendor_Events來獲取相應的行

高溫高壓

引用自:https://dba.stackexchange.com/questions/157979