查找未在最近k天内有效更新的记录

时间:2014-11-20 15:15:50

标签: mysql optimization query-optimization

我有一张表格,其中包含最后 n 天的记录。该表中的记录约为1亿。我需要找到最后k中没有更新的记录

我对此问题的解决方案是

将表格分区为k1。时间戳列索引。现在,不要更新时间戳(以便不重建索引),而是执行remove + insert。通过这样做,我认为查找未在最近k天更新的记录的查询将很快。

还有其他更好的方法来优化这些操作吗?

例如,

假设我们有很多用户,每个用户都可以使用不同的产品。用户也可以随时开始使用(成为所有者)新产品。如果用户在n天内未使用产品,则其所有权到期。现在我们需要找到用户在过去k天内未使用过的所有产品。用户数量为10000,他可以选择的产品数量为100,000。

我使用架构(user_id,product_id,last_used)的表格对此问题进行了建模。 product_id 是用户正在使用的产品的ID。每当用户使用产品时,last_used都会更新。如果用户未使用n天,则用户对产品的所有权也会过期。我在user_id上的表上进行了分区,并将last_used(timestamp)编入索引。而不是更新我执行删除+创建。我为优化查询进行了分区和索引,以便获取用户在过去k天内未更新的记录。

有没有更好的方法来解决这个问题?

2 个答案:

答案 0 :(得分:0)

你说你需要"找到"而且,我认为"到期"在特定天数后属于特定用户的记录。

看,这可以在一个具有良好索引的大表中完成,而不会有太多麻烦。我向你保证,对表进行分区将是一个麻烦。您已断言,由于更新,您的last_used列中的索引在您的应用程序中过于昂贵。但是,考虑到维护分区表的初始和持续费用,我强烈建议您首先证明断言。您可能错误地维护索引的成本。

(使用索引的列更新一行并不重建索引,它会对其进行修改.MySQL存储引擎开发人员已经优化了该用例,我向您保证。)

我相信您知道,此查询将检索特定用户的旧记录。

SELECT product_id 
   FROM tbl
  WHERE user_id = <<<chosen user>>>
    AND last_used <= CURRENT_DATE() - <<<k>>> DAY

将生成您的产品列表。如果你在(user_id, last_used, product_id)上有一个复合覆盖索引,这将非常有效。如果你不知道复合覆盖索引是什么,你真的应该找到你最喜欢的搜索引擎。这个将随机访问特定用户,然后在last_used日期进行范围扫描。然后它将从索引中返回产品ID。

如果你想要删除所有旧记录,我建议你编写一个宿主程序,在循环中重复这个查询,直到你发现它已经处理了零行。在应用程序的非高峰时间运行此操作。 LIMIT子句将阻止每个单独的查询花费太长时间并干扰表的其他用法。为了提高此查询的速度,您需要last_used上的索引。

DELETE FROM tbl
 WHERE last_used <= CURRENT_DATE() - <<<k>>> DAY
 LIMIT 500

我希望这会有所帮助。它来自于那些试图对不需要分区的东西进行分区的代价高昂的错误。

答案 1 :(得分:0)

修改索引值时,MySQL不会“重建”索引(不完全)。事实上,它甚至没有重新排序记录。它只是将记录移动到适当的16KB页面。

在页面中,记录按添加顺序排列。如果按顺序插入,则它们按顺序排列,否则它们不是。

因此,当他们说MySQL的聚簇索引是物理顺序时,它只能在页面级别下,但不在页面内。

聚簇索引仍然可以获得页面数据与索引位于同一页面上的好处,因此如果行数据足够小以适应页面,则不需要进一步查找。读取速度更快,但重组速度较慢,因为您必须使用索引移动数据。二级索引的更新速度要快得多,但要实际检索数据(覆盖索引除外),必须进一步查找以通过二级索引产生的主键检索实际数据。

示例

第1页可能会为姓氏以A到B开头的人保留用户记录.Page 2可能包含名称C到D等。如果Bob重命名自己Chuck,他的记录会从第1页复制到第2页。他的记录将始终放在第2页的末尾。密钥保持排序,但不是他们指向的数据。

如果页面已满,MySQL将拆分页面。在这种情况下,假设在C和D之间均匀分布,第1页将是A到B,第2页将是C,第3页将是D.

当删除记录时,空间被压缩,如果记录小于半满,MySQL将合并相邻页面,并可能在中间释放一个页面。

所有这些更改都是缓冲的,MySQL在不忙时会执行实际写入。

该示例对于聚簇(主要)和辅助索引的工作原理相同,但请记住,对于聚簇索引,键指向实际的表数据,而使用辅助索引时,键指向的值等于主键。

<强>摘要

一段时间后,由随机插入引起的页面拆分将导致页面在磁盘上变得不连续。该表将变得“支离破碎”。优化表(重建表/索引)可以解决这个问题。

删除然后重新插入记录没有任何好处。实际上,您只需添加事务开销。让MySQL处理为你更新索引。

既然您已经了解了更多索引,也许您可​​以更好地决定如何优化数据库。