Mysql
調查慢查詢的工具/方法
我有一個帶有子查詢的查詢,兩者都很快,但是當它們結合起來時,它們需要永遠(意味著任何時間超過我的應用程序可接受的時間)。我嘗試使用“解釋”來查看發生了什麼,但對我沒有多大幫助。還有哪些其他方法可以調查慢查詢?
以下是我的問題的具體細節。我有一個產品列表,我想找到每個產品的第一個供應商活動的日期。如果我得到事件 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
來獲取相應的行高溫高壓