[英]MYSQL&PHP: running an INSERT INTO SELECT query within a PHP while loop, running slow
我對php和MYSQL真的很陌生,一個月前我都不了解,所以請原諒我草率/可憐的代碼:)
我的PHP中包含以下代碼:
$starttime = microtime(true);
$q_un = 'SELECT i.id AS id
FROM items i
WHERE i.id NOT IN (SELECT item_id FROM purchased_items WHERE user_id=' . $user_id . ')';
$r_un = mysqli_query($dbc, $q_un);
if (mysqli_num_rows($r_un) > 0) {
while ($row_un = mysqli_fetch_array($r_un, MYSQLI_ASSOC)) {
$item_id = $row_un['id'];
$q_rec = 'INSERT INTO compatibility_recommendations (
`recommendation`,
`user_id`,
`item_id`)
SELECT
((SUM(a.rating*(a.compat-80)))/(SUM(a.compat-80)))*10 AS rec,
a.user_id AS user_id,
a.item_id AS item_id
FROM
(SELECT r.rating AS rating,
c.user2_id AS rater,
c.user1_id AS user_id,
c.compatibility AS compat,
r.item_id AS item_id
FROM ratings r
RIGHT JOIN compatibility_ratings c ON r.user_id=c.user2_id
WHERE c.user1_id=' . $user_id . ' AND r.item_id=' . $item_id . ' AND c.compatibility>80) a
ON DUPLICATE KEY UPDATE
recommendation = VALUES(recommendation)';
$r_rec = mysqli_query($dbc, $q_rec);
}
}
$endtime = microtime(true);
$duration = $endtime - $starttime;</code>
第一個查詢選擇當前用戶$ user_id尚未購買的商品列表。 然后,我在返回的每一行(項目)上運行while循環,在該循環內執行主查詢。
下一個查詢從等級表中獲取信息,其中item_id等於要查詢的當前item_id,然后通過右聯接將其聯接到預先計算的用戶兼容性表中。
然后,我對等級和兼容性等級進行算術運算以形成推薦值,然后將推薦item_id和user_id插入另一個表中,以便稍后調用。 (item_id,user_id)列上有2列唯一鍵,因此最后是ON DUPLICATE KEY UPDATE
所以我今天早上寫了這段代碼,對自己很滿意,因為它確實滿足了我的要求。
問題是,可以預見的是,它很慢。 在我的測試數據庫中,有5個測試用戶和100個測試項目,以及200個評分的隨機組合,整個while循環需要2.5秒。 我以為它會很慢,但不會那么慢。 一旦添加了更多用戶和項目,這真的很艱難。 主要問題在於插入...在重復密鑰更新部分,我的磁盤利用率達到了100%,我可以告訴我筆記本電腦的HDD正在瘋狂地尋找。 我知道我可能會在生產中使用SSD,但是我仍然預計會出現成千上萬個項目和用戶的大規模問題。
因此,我的主要問題是:任何人都可以就如何優化我的代碼或完全調整速度以提高速度提供任何建議。 我敢肯定,while循環內的插入查詢是一種糟糕的方法,我只是想不出任何其他方法來獲得完全相同的結果
在此先感謝您,如果我對問題的格式不正確,請對不起
我在這里找到了想要的答案
每個項目的第二個查詢僅花費選擇時間0.002秒,但插入后花費0.06秒,因此我對查詢進行了分析,發現“查詢結束”花費了99%的查詢時間。 我已經設置了innodb_flush_log_at_trx_commit = 0,但是對該答案的評論卻一無所獲。 但是,我不使用交易,所以這種方法會產生任何后果/替代方法嗎? 確實將我的while循環時間從2.5秒減少到0.08秒。
$starttime = microtime(true);
$q_un = "
INSERT INTO compatibility_recommendations
(recommendation
,user_id
,item_id
)
SELECT ((SUM(a.rating*(a.compat-80)))/(SUM(a.compat-80)))*10 rec
, a.user_id
, a.item_id
FROM
( SELECT r.rating rating
, c.user2_id rater
, c.user1_id user_id
, c.compatibility compat
, r.item_id
FROM compatibility_ratings c
JOIN ratings r
ON r.user_id = c.user2_id
JOIN items i
ON i.id = r.item_id
LEFT
JOIN purchased_items p
ON p.item_id = i.id
AND p.user_id = $user_id
WHERE c.user1_id = $user_id
AND c.compatibility > 80
AND p.item_id IS NULL
) a
GROUP BY a.item_id
ON DUPLICATE KEY UPDATE recommendation = VALUES(recommendation);
";
$r_rec = mysqli_query($dbc, $q_rec);
}
}
$endtime = microtime(true);
$duration = $endtime - $starttime;</code>
對於任何進一步的改進,我們確實需要查看正確的DDL和上面的SELECT的解釋。
參見https://stackoverflow.com/a/14456661/2782404
fetch_assoc可能比fetch_array快得多,因此您應該在訪問值之前一次提取所有內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.