我有两个数据库表,我用它来创建一个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语句中的某处有错误,但我稍后会担心.)
如果我用shop_name替换feed_id,我可以用这个替换第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列转换为复合主键.这样您就可以自动防止重复订阅.
>将一个活动列…一个短整数…添加到表中.当它设置为值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值.它可以通过从随机访问索引的位置扫描索引来实现,而无需返回表格.这确实非常快.它被称为覆盖指数.
另一个覆盖索引处理以已知用户开头并继续查找提要的查询.索引中列的顺序很重要:随机访问只能从索引的第一个(最左边)列开始.
要理解的技巧是这些索引是随机可访问的并且可以顺序扫描.
另一个注意事项如果连接表中只有两列,则其中一个覆盖索引也是主键,另一个包含与主键相反的列.您不需要任何重复索引.