我有一个表跟踪每个用户点击的链接,我有另一个表链接。这是每个表结构:
链接: id |链接|价值| DATE_ADDED
已点击: user_id | link_id | date_clicked
现在这是我用来使我的搜索发生并且有效的代码,我只是想知道是否有更有效的方法,因为点击的链接表会变得非常快
$history_query = mysql_query("SELECT * FROM clicked_links WHERE user_id = '$id'") or die(mysql_error());
$history_array = array();
while ($h = mysql_fetch_array($history_query)) {
$history_array[] = $h['link_id'];
}
$clicked = implode(',', $history_array);
$link_query = mysql_query("SELECT * FROM chip_links WHERE id NOT IN ($clicked) ORDER BY value DESC") or die(mysql_error());
while ($r = mysql_fetch_array($link_query)) {
echo "<div id='claim{$r['id']}' style='text-align: center; font-weight: bold; font-size: 18px; float: left; width: 183px;'>
<a href='{$r['link']}' id='{$r['id']}' class='collect' target='_blank'>
Claim {$r['value']} points!
</a>
</div>";
}
答案 0 :(得分:1)
运行单个查询来获取结果集会更有效,而不是运行单独的查询。
您不需要返回所有link_id
值,将它们放入数组中,将数组放入字符串中,然后将该字符串推送到另一个查询中,然后将其重新打包回数据库...数据库已经有了。
此查询将返回与当前$ link_query等效的结果集,而不需要$ history_query或$ history_array。
SELECT l.id
, l.link
, l.value
FROM chip_links l
WHERE l.id NOT IN
( SELECT c.link_id
FROM clicked_links c
WHERE c.user_id = '$id'
AND c.link_id IS NOT NULL
)
ORDER BY l.value DESC
如果您没有某种保证clicked_links表中的link_id不是NULL,那么您将希望在该子查询中包含link_id IS NOT NULL
谓词,因为如果查询不返回任何行, link_id值为NULL。 (这是NOT IN (subquery)
构造的一个众所周知且可避免的问题。
MySQL可能会将其优化为(希望更有效但是)等效的NOT EXISTS相关子查询,如下所示:
SELECT l.id
, l.link
, l.value
FROM chip_links l
WHERE NOT EXISTS
( SELECT 1
FROM clicked_links c
WHERE c.user_id = '$id'
AND c.link_id = l.id
)
ORDER BY l.value DESC
但为了获得最佳性能,您可能希望使用反连接模式。
LEFT JOIN操作基本上查找匹配的行,而IS NOT NULL
谓词将抛出匹配的行,所以你得到的是来自chip_links
的行,其中没有“匹配”的行clicked_links
。
MySQL优化器通常使用如下查询生成最有效的计划:
SELECT l.id
, l.link
, l.value
FROM chip_links l
LEFT
JOIN clicked_links c
ON c.link_id = l.id
AND c.user_id = '$id'
WHERE c.link_id IS NULL
ORDER
BY l.value DESC
为了在大型集合上获得良好的性能,您还可能需要索引
... ON clicked_links (user_id, link_id)
... ON chip_links (value, id, link)
这应该允许从索引完全满足查询,而不需要排序操作。 EXPLAIN输出将包含“使用索引”,并且不包括“使用filesort”。
答案 1 :(得分:0)
这样的一次性查询会告诉您给定用户未点击的所有链接
SELECT l.* FROM chip_links l
LEFT JOIN clicked_links c ON (c.link_id=l.id AND l.user_id='$id')
WHERE c.link_id IS NULL
ORDER BY l.value DESC;
如果你不熟悉左连接,它将包含来自clicked_links的行,其中join子句匹配,但是我们没有得到匹配,我们只会得到空值。由于我们对不匹配感兴趣,因此WHERE子句确保这些是我们将获得的唯一行。
使用两个查询和一些PHP代码可能会更有效,但只有基准测试才能确定。您还应检查EXPLAIN SELECT ...
的输出,以确保使用合适的索引。