我有两个数据库表,我用它来创建一个Twitter风格的跟随系统。
sh_subscriptions
=> id
=> user_id
=> feed_id
sh_feeds
=> id
=> item
=> shop_name
=> feed_id
在feed_id
中存储shop_name
而不是sh_subscriptions
的问题在于它需要大量表格加入:
$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
会更快}?
答案 0 :(得分:2)
您的sh_subscriptions表实际上是一个多用户连接表,用于将用户与Feed相关联。这被认为是设计数据库模式的好方法。
您的基本概念是:您拥有一组用户和一组供稿。每个用户可以订阅零个或多个订阅源,每个订阅源可以包含零个或多个订阅者。
要输入订阅,请在sh_subscriptions表中创建一行。要取消它,请删除该行。
你说有很多桌子加入。相对而言,这并不是很多表加入。 MySQL是为这种加入而制作的,它会很好用。
我对你的sh_subscriptions表有一些建议。
id
列。而是将user_id和feed_id列转换为复合主键。这样您就可以自动防止重复订阅。active
列...短整数....当它设置为值1
时,您的Suscription处于活动状态。这样,您可以通过将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值。它可以通过从随机访问索引的位置扫描索引来实现,而无需返回表格。这确实非常快。它被称为覆盖索引。
另一个覆盖索引处理以已知用户开头并继续查找提要的查询。索引中列的顺序很重要:随机访问只能从索引的第一个(最左边)列开始。
要理解的诀窍是这些索引既可以随机访问,也可以顺序扫描。
另一个注释如果连接表中只有两列,则其中一个覆盖索引也是主键,另一个包含与主键相反的列。您不需要任何重复的索引。