我真的是 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,并使用右连接将其连接到预先计算的用户兼容性表。
然后我对ratings和compatibility ratings进行运算,形成一个推荐值,然后将recommendation,item_id和user_id插入到另一个表中,稍后调用。在 (item_id,user_id) 列上有一个 2 列唯一键,因此最后是 ON DUPLICATE KEY UPDATE
所以我今天早上写了这段代码,我对自己很满意,因为它完全满足了我的需要。
问题是,不出所料,它很慢。在我的测试数据库中,有 5 个测试用户和 100 个测试项目以及随机分类的 200 个评级,运行 while 循环需要 2.5 秒。我原以为它会很慢,但没有这么慢。一旦添加了更多的用户和项目,它真的会很挣扎。主要问题是插入...在重复 key 更新部分,我的磁盘利用率达到 100%,我可以看出我的笔记本电脑的 HDD 正在疯狂地寻找。我知道我可能会在生产中使用 SSD,但我仍然预计会有数千个项目和用户出现大规模问题。
所以我的主要问题是:任何人都可以就如何优化我的代码或完全重新调整以提高速度提出任何建议。我确信在 while 循环中插入查询是一种糟糕的方法,我只是想不出任何其他方法来获得完全相同的结果
提前致谢,如果我的问题格式不正确,我深表歉意
最佳答案
$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 的 EXPLAIN。
关于php - MYSQL&PHP : running an INSERT INTO SELECT query within a PHP while loop, 运行缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26789524/