【问题标题】:Storing and fetching cities that user have visited (for millions of users) mysql - php存储和获取用户访问过的城市(数百万用户)mysql - php
【发布时间】:2012-08-06 04:25:07
【问题描述】:

我想存储用户访问过的城市。在个人资料页面中,将列出用户访问过的所有城市。并且会有一个功能,用户可以搜索“谁访问过那个城市”(可以有多个城市搜索)

我打算建立多对多关系。

Table Users
-----------
UserID
UserName
...


Table Cities
-------
CityID
CityName
....


Table City_Relations
-----------
UserID
CityID

在个人资料页面中,我可以运行一个简单的查询来获取城市。

select c.cityname FROM city_relations cr left join cities c on ( c.cityid = cr.cityid ) where cr.userid = 'USERID'

并在搜索页面中获取访问过所选城市的用户;

select u.username FROM city_relations cr left join users u on ( u.userid = cr.userid ) where cr.cityid = 'CITYID'   ( there may be cr.cityid = '1' or cr.cityid = '2' and so on; or in()/find_in_set()  ) 

到目前为止一切正常。我的问题是这效率如何?假设有 1 亿用户,每个用户在 city_relations 表中可以有数百个城市。假设每个用户有 100 个城市,那么该表中将有 100 亿行将运行插入/删除和选择 - 连接查询。

如果这种方式可行,我应该记住什么才能获得最佳性能?表上的索引就足够了吗? 如果这种方式可能会导致问题,您还有什么建议?

您如何看待“不将所有关系存储在不同的行中并将它们保存在一个字段中”?

For example;
-----------
UserID
CityIDS (separated by commas)

【问题讨论】:

  • 祝你好运,获得 1 亿用户

标签: mysql list store


【解决方案1】:

如果您可以将city 存储在不同的行中会更好。虽然mysql中存在find_in_set()这样的内置函数,但是如果你尝试另一个数据库服务器,它就不够灵活。而且您说的是数十亿行而不是数百万行。所以这里查询的效率是最重要的。

【讨论】:

    【解决方案2】:

    重要的是索引 city_relations 中的两列。由于 UserID,CityID 可能是表的唯一主键,因此您不需要为 UserID 附加索引(索引是 B 树,因此索引列集的任何前缀也会被索引),但您将需要自己的 CityID 索引。

    我同意约翰的观点,即您应该将城市分开排列。 find_in_set() 不能利用索引,所以它必须搜索每一行并执行复杂的字符串搜索。

    【讨论】:

    • 所以你说的是添加主键 (userid,cityid)。 'users' 表和 'cities' 表中有 id 的索引。对于这种情况,在主键更改后添加 KEY userid (userid)、KEY cityid (cityid) 会发生什么变化? (为了更好的性能)
    • 我的建议是PRIMARY KEY (userid, cityid), KEY (cityid)。您不需要KEY (userid),因为这已经由主键隐式提供。添加这个额外的密钥只会占用多余的空间和时间。
    • 我完全按照你说的做了。如您所说,创建并索引表。用户表有 1.5m 行,关系表有 100m 行。现在SELECT u.username FROM users u LEFT JOIN city_relations c ON (u.userid = c.userid) WHERE c.cityid = 87 order by u.userid desc limit 100 这个查询最多返回 8 秒。我怎样才能减少它?签名外键可以减少吗?
    • 我假设 userid 是 users 表的主键。如果没有,它应该是。另外,city_relations 中有多少行的 cityid 为 87?如果结果很大,时间可能来自对结果进行排序。
    • 是的,userid 是 cityid 的主键。有 100 万行的 cityid 为 87。这样查询结果来得太慢了。我更改了联接,它现在返回更快。(0.10 秒)但是我使用 group byhaving SELECT userid, count( userid ) AS cnt FROM city_relations WHERE status ='1' GROUP BY userid HAVING cnt = 10 LIMIT 10 对该表有不同的问题,此查询基本上不返回任何内容,它太慢了所以我重新启动mysql服务器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-31
    • 1970-01-01
    • 2016-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-30
    相关资源
    最近更新 更多