需要帮助优化基本连接操作,在100K +行的表上

时间:2013-10-04 22:04:56

标签: mysql sql database database-design

我正在尝试为特定实体创建状态/消息更新页面。用户可以 订阅任意数量的实体,在此页面上您将获得最新信息。 我当前的查询需要一段时间才能运行(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

在订阅表上,我得到以下解释信息:使用索引;使用临时;使用filesort

我正在使用InnoDB表,我在entity_id,user_id和timestamp列上有索引

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

更新:当我删除order by子句时,查询会快速运行。 .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 

3 个答案:

答案 0 :(得分: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相对应的订阅,即少量数据。

答案 1 :(得分:0)

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

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

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

答案 2 :(得分: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