0

我正在尝试为特定实体创建状态/消息更新页面。用户可以订阅任意数量的实体,在此页面上您将获得最新信息。我当前的查询需要一段时间才能运行(1.3+ 秒,在一个有 200K 行的测试表中),它只抓取了 50 左右行

架构是:

实体:

  entity_id, message, timestamp

用户

  user_id

订阅

  user_id, entity_id

查询是:

   SELECT entity.*
   FROM entity
   INNER JOIN subscription ON subscription.entity_id = entity.entity_id
   WHERE subscription.user_id = 1
   ORDER BY entity.timetamp DESC 
   LIMIT 50

数据库方面的问题似乎是这样的:

   Copying to tmp table 0.033285
   converting HEAP to MyISAM    0.031850
   Copying to tmp table on disk 1.177973
   Sorting result   0.064075

在订阅表上,我得到以下解释信息:使用索引;使用临时的;使用文件排序

我正在使用 InnoDB 表,并且在 entity_id、user_id 和时间戳列上有索引

更新:看来 order by 可能是有贡献的,或者是问题所在。我在时间戳列上有一个索引,除此之外,我还能做些什么来更快地获取最新消息?

更新:当我删除 order by 子句时,查询运行得很快。0.0006 秒 vs 1.3。所以我尝试先通过子查询获取数据,然后运行 ​​order by,但这并没有做任何事情。

使用的查询是:

SELECT tbl.* FROM ( 
   SELECT entity.*
   FROM entity
   INNER JOIN subscription ON subscription.entity_id = entity.entity_id
   WHERE subscription.user_id = 1
) as tbl
ORDER BY tbl.timetamp DESC 
4

3 回答 3

0

只需确保您的意思不是每个 EntityID 的 TOP 50,在这种情况下,查询将非常不同。您在查询中使用 LIMIT 的方式意味着您最多将获得按时间戳排序的 50 行。

如果第二个为真,那么您只能在第一次过滤大表。此外,如果您在查询中使用“Order By”,请尝试提出可在 WHERE 条件下使用的常量/列表。这样数据库引擎可以更有效地利用索引。

您需要的索引。

表实体:

TimeStamp DESC, EntityID ASC, Message ASC

表订阅:

User_id,entity_ID

试试这个查询

    SET @Rownum=1
    SET @PValue=''

    SELECT Entity_ID,Message,TIMESTAMP
    FROM
    (
        SELECT
            @Rownum:=IF(@Timestamp=Timestamp, @Rownum+1,1) AS RowNumber
            ,Entity_ID
            ,MESSAGE
            ,TimeStamp
            @Timestamp=@Timestamp AS DummyTimeStamp
        FROM Enitty
        WHERE Entity_ID IN (SELECT Entity_ID FROM Subscription WHERE USER_ID = 1)
        ORDER BY Timestamp DESC
    )qry
    WHERE RowNumber <=50
于 2013-10-05T03:03:45.847 回答
0

你可以试试这个查询:

SELECT entity.* FROM
entity
INNER JOIN 
 (SELECT *
  FROM subscription 
  WHERE user_id = 1
 ) AS subscriptions_for_user ON subscriptions_for_user.entity_id = entity.entity_id
ORDER BY entity.timetamp DESC 
LIMIT 50

这样,您只需加入与 user_id 相对应的订阅,即数据量较少。

于 2013-10-04T22:10:59.180 回答
0

在实体表中,您需要一个涵盖 entity_id 和时间戳的单个索引顺序排列。如果这是主键最好。在订阅表上,您需要一个按该顺序同时涵盖user_id 和 entity_id的索引。重要的是,这些索引包含同一索引中的两列。

完成后,您要确保让 MySql 有足够的 RAM 以便能够将表和索引完整地保存在 RAM 中,然后运行一些示例查询以“预热”数据库缓存之前做你的实际基准。

我还建议您需要一个与实体表分开的消息表,这实际上是您将在此处查看的消息表。

于 2013-10-04T23:03:24.907 回答