我有两个数据库表,我正在使用它们来创建一个 Twitter 风格的关注系统。
sh_subscriptions
=> id
=> user_id
=> feed_id
sh_feeds
=> id
=> item
=> shop_name
=> feed_id
在 sh_subscriptions
中存储 feed_id
而不是 shop_name
的问题是它需要大量的表连接:
$id = $_POST['id'];
$user_id = $id['id'];
$shop_name = mysqli_escape_string($con, $_POST['shop_name']);
$query = "SELECT * FROM sh_subscriptions s INNER JOIN sh_feeds f ON s.feed_id = f.feed_id WHERE s.user_id = $user_id AND f.shop_name = '$shop_name'";
$result = mysqli_query($con, $query) or die(mysqli_error($con));
if (mysqli_num_rows($result) > 0)
{
$query2 = "DELETE FROM sh_subscriptions s INNER JOIN sh_feeds f ON s.feed_id = f.feed_id WHERE s.user_id = $user_id AND f.shop_name = '$shop_name'";
$result2 = mysqli_query($con, $query2) or die(mysqli_error($con));
}
else
{
// insert the row instead
}
(我知道 if 语句中某处有错误,但稍后我会担心。)
如果我将 feed_id
替换为 shop_name
,我可以将第 5 行替换为:
$query = "SELECT * FROM sh_subscriptions WHERE user_id = $user_id AND shop_name = '$shop_name'";
我的问题是:是否总是尽可能将 MySQL 值存储为整数,或者在这种情况下,让 sh_subscriptions
包含 shop_name
会更快吗而不是 feed_id
?
最佳答案
您的 sh_subscriptions 表实际上是一个将用户与提要相关联的多对多连接表。这被认为是设计数据库模式的好方法。
您的基本概念是:您有一组用户和一组提要。每个用户可以订阅零个或多个提要,每个提要可以有零个或多个订阅者。
要输入订阅,您需要在 sh_subscriptions 表中创建一行。要取消它,请删除该行。
你说有“很多表连接”。恕我直言,这不是很多表连接。 MySQL 就是为这种连接而生的,它会很好地工作。
我对您的 sh_subscriptions 表有一些建议。
- 去掉
id
列。而是将 user_id 和 feed_id 列变成复合主键。这样您将自动防止重复订阅。 - 添加一个
active
列 ... 一个短整数 ... 到表中。当它设置为1
时,您的订阅处于事件状态。这样您就可以通过将active
设置为 0 来取消订阅。 - 如果您关心的话,您还可以添加一个
subscribed_date
列。 - 在表上创建两个复合非唯一索引
(active,user_id,feed_id)
和(active,feed_id,userId)
。这些将大大加快像这样连接表的查询。
查询片段:
FROM sh_feed f
JOIN sh_subscription s ON (f.feed_id = s.feed_id AND s.active = 1)
JOIN sh_users u ON (s.user_id = u.user_id)
WHERE f.shop_name = 'Joe the Plumber'
如果您达到了拥有数亿用户或提要的地步,您可能需要考虑对该表进行非规范化。也就是说,例如,重新定位商店名称文本,使其位于 sh_subscriptions 表中。但不是现在。
编辑 我建议使用多个复合覆盖索引。例如,如果您要加入用户提要,MySQL 会通过确定 sh_feeds 中与您的选择匹配的行来开始满足您的查询。
然后它确定 feed_id,并随机访问 feed_id 上的复合索引。然后,它需要查找该 feed_id 的所有 user_id 值。它可以通过从随机访问索引的点开始扫描索引来做到这一点,而无需返回到表中。这确实非常快。它称为覆盖索引。
另一个覆盖索引处理从已知用户开始并继续查找提要的查询。索引中列的顺序很重要:随机访问只能从索引的第一列(最左边)开始。
要理解的技巧是这些索引既可以随机访问又可以顺序扫描。
另一个注意事项 如果连接表中只有两列,覆盖索引之一也是您的主键,另一个包含与主键相反顺序的列。您不需要任何重复索引。
关于php - 将 MySQL 值存储为整数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23472191/