簡體   English   中英

MySQL 查詢 IN() 子句在索引列上變慢

[英]MySQL Query IN() Clause Slow on Indexed Column

我有一個由 PHP 腳本生成的 MySQL 查詢,查詢將如下所示:

SELECT * FROM Recipe_Data WHERE 404_Without_200 = 0 AND Failures_Without_Success = 0 AND RHD_No IN (10, 24, 34, 41, 43, 51, 57, 59, 61, 67, 84, 90, 272, 324, 402, 405, 414, 498, 500, 501, 510, 559, 562, 595, 632, 634, 640, 643, 647, 651, 703, 714, 719, 762, 765, 776, 796, 812, 814, 815, 822, 848, 853, 855, 858, 866, 891, 920, 947, 956, 962, 968, 1049, 1054, 1064, 1065, 1070, 1100, 1113, 1119, 1130, 1262, 1287, 1292, 1313, 1320, 1327, 1332, 1333, 1335, 1340, 1343, 1344, 1346, 1349, 1352, 1358, 1362, 1365, 1482, 1495, 1532, 1533, 1537, 1549, 1550, 1569, 1571, 1573, 1574, 1596, 1628, 1691, 1714, 1720, 1735, 1755, 1759, 1829, 1837, 1844, 1881, 1919, 2005, 2022, 2034, 2035, 2039, 2054, 2076, 2079, 2087, 2088, 2089, 2090, 2091, 2092, 2154, 2155, 2156, 2157, 2160, 2162, 2164, 2166, 2169, 2171, 2174, 2176, 2178, 2179, 2183, 2185, 2186, 2187, 2201, 2234, 2236, 2244, 2245, 2250, 2255, 2260, 2272, 2280, 2281, 2282, 2291, 2329, 2357, 2375, 2444, 2451, 2452, 2453, 2454, 2456, 2457, 2460, 2462, 2464, 2465, 2467, 2468, 2469, 2470, 2473, 2474, 2481, 2485, 2487, 2510, 2516, 2519, 2525, 2540, 2545, 2547, 2553, 2571, 2579, 2580, 2587, 2589, 2597, 2602, 2611, 2629, 2660, 2662, 2700, 2756, 2825, 2833, 2835, 2858, 2958, 2963, 2964, 3009, 3090, 3117, 3118, 3120, 3121, 3122, 3123, 3126, 3127, 3129, 3130, 3133, 3135, 3137, 3138, 3139, 3141, 3142, 3145, 3146, 3147, 3151, 3152, 3155, 3193, 3201, 3204, 3219, 3221, 3222, 3223, 3224, 3225, 3226, 3227, 3228, 3229, 3231, 3232, 3233, 3234, 3235, 3237, 3239, 3246, 3250, 3253, 3259, 3261, 3291, 3315, 3328, 3377, 3381, 3383, 3384, 3385, 3387, 3388, 3389, 3390, 3396, 3436, 3463, 3465, 3467, 3470, 3471, 3484, 3507, 3515, 3554, 3572, 3641, 3672, 3683, 3689, 3690, 3692, 3693, 3694, 3697, 3698, 3705, 3711, 3713, 3715, 3716, 3717, 3719, 3720, 3722, 3726, 3727, 3732, 3737, 3763, 3767, 3770, 3771, 3772, 3773, 3803, 3810, 3812, 3816, 3846, 3847, 3848, 3851, 3874, 3882, 3902, 3903, 3906, 3908, 3916, 3924, 3967, 3987, 4006, 4030, 4043, 4045, 4047, 4058, 4067, 4107, 4108, 4114, 4115, 4131, 4132, 4133, 4137, 4138, 4139, 4140, 4141, 4142, 4146, 4150, 4151, 4152, 4153, 4157, 4158, 4160, 4163, 4166, 4167, 4171, 4179, 4183, 4221, 4225, 4242, 4257, 4435, 4437, 4438, 4443, 4446, 4449, 4450, 4451, 4452, 4454, 4460, 4550, 4557, 4618, 4731, 4775, 4804, 4972, 5025, 5026, 5039, 5042, 5294, 5578, 5580, 5599, 5602, 5649, 5726, 5779, 5783, 5931, 5934, 5936, 5939, 5940, 5941, 5978, 6044, 6056, 6113, 6116, 6118, 6122, 6123, 6125, 6127, 6128, 6129, 6130, 6131, 6135, 6141, 6145, 6147, 6150, 6152, 6153, 6154, 6160, 6166, 6169);

RHD_No 列是這個數據庫的主鍵,總共有大約 400,000 行。 問題是,查詢速度非常慢,通常在 2 秒左右,但我已經看到它長達 10 秒。

當我嘗試解釋查詢時,一切似乎都應該沒問題:

+----+-------------+-------------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table       | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-------------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | Recipe_Data | range | PRIMARY       | PRIMARY | 4       | NULL |  420 | Using where |
+----+-------------+-------------+-------+---------------+---------+---------+------+------+-------------+

當我分析查詢時,我得到:

mysql> show profile;
+--------------------------------+----------+
| Status                         | Duration |
+--------------------------------+----------+
| starting                       | 0.000015 |
| checking query cache for query | 0.000266 |
| Opening tables                 | 0.000009 |
| System lock                    | 0.000004 |
| Table lock                     | 0.000006 |
| init                           | 0.000115 |
| optimizing                     | 0.000038 |
| statistics                     | 0.000797 |
| preparing                      | 0.000047 |
| executing                      | 0.000002 |
| Sending data                   | 2.675270 |
| end                            | 0.000007 |
| query end                      | 0.000003 |
| freeing items                  | 0.000071 |
| logging slow query             | 0.000002 |
| logging slow query             | 0.000058 |
| cleaning up                    | 0.000005 |
+--------------------------------+----------+

我已經在這個問題上工作了很長時間,但我一直無法找到解決方案。 這個查詢有什么明顯的錯誤嗎? 我不明白查看 420 行需要 2 秒以上的時間。

您正在通過主鍵訪問 420 行,這可能會導致索引訪問路徑。 這可以為每個鍵訪問 2 個索引頁和一個數據頁。 如果這些在緩存中,查詢應該運行得很快。 否則,進入磁盤的每個頁面訪問都會導致通常的磁盤延遲。 如果我們假設 5 毫秒的磁盤延遲和 80% 的緩存命中率,我們會得到 420*3*0.2*5ms=1.2 秒,這與您所看到的差不多。

問題是IN基本上被視為一堆OR s(例如

col IN (1,2,3)

col = 1 OR col = 2 OR col = 3

這比連接慢很多。

您應該做的是生成創建臨時表的 SQL 代碼,用“IN”子句中的值填充它,然后與該臨時表連接

CREATE TEMPORARY TABLE numbers (n INT)

然后在循環中,添加

INSERT numbers  VALUES ($next_number)

然后在最后

SELECT * FROM numbers, Recipe_Data 
WHERE numbers.n = RHD_No

您應該將 IN 子句轉換為 INNER JOIN 子句。

您可以轉換這樣的查詢:

SELECT  foo   
FROM    bar   
WHERE bar.stuff IN  
       (SELECT  stuff FROM asdf)

進入這樣的查詢:

SELECT  b.foo 
FROM    ( 
        SELECT  DISTINCT stuff 
        FROM    asdf ) a 
JOIN    bar b 
ON      b.stuff = a.stuff

您將獲得很多性能。

當 php 生成查詢時,嘗試某種技巧,例如為 IN 子句中的項目創建臨時表。 如果可以,請始終盡量避免使用 IN 子句,因為它們非常耗時。

我打算在這里賭一把,並建議只執行一次以下查詢以創建適合您查詢的索引應該將查詢時間減少至少一秒鍾......

CREATE INDEX returnstatus ON Recipe_Data(404_Without_200,Failures_Without_Success)

請參閱: http : //dev.mysql.com/doc/refman/5.0/en/create-index.html創建索引,以及http://dev.mysql.com/doc/refman/5.0/en/mysql- index.html了解如何在查詢中使用索引。

如果失敗,請查看 mysql 上所有正在運行的進程,以查看來自任何來源的當前正在運行的查詢是否只是在消耗服務器的所有時間並殺死它的同時拒絕終止。 見: http : //dev.mysql.com/doc/refman/5.0/en/kill.html

如果做不到這一點,請確定每條記錄還有哪些共同點,以避免在IN語句中通過 ID 號單獨引用每條記錄。 如有必要,添加另一個表格列以跟蹤該共性。 然后,將具有該共性的列添加到上述索引中,並在您的WHERE子句中過濾,而不是使用IN語句。 例如,如果您只想在頁面上打印這些 ID 號,則將visible列作為類型​​: tinyint其中值0排除,值1包括在搜索結果中,然后將visible列添加到索引WHERE子句中以加快查詢速度。 你根本不需要那個IN語句。

也許您的in語句是使用先前的查詢動態構建的。 如果是這種情況,請嘗試使用Recipe_Data WHERE 404_Without_200 = 0 AND Failures_Without_Success = 0拉取所有行。 然后在您的 PHP 腳本中,如果RHD_No與預期值不匹配,則只需丟棄 fetch 循環中的記錄。

對於像我這樣使用 SQlAlchemy 的人來說,使用 for 循環也是一個不錯的選擇:

rows=[]

for id in ids:
  row = cls.query.filter(cls.id==id).first()
  if row:
     rows.append(row)

#return rows

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM