SQL LIMIT获取最新记录

时间:2012-01-17 07:53:46

标签: mysql sql sql-order-by limit greatest-n-per-group

我正在编写一个脚本,列出所有12个类别中的25个项目。数据库结构如下:

tbl_items
---------------------------------------------
item_id | item_name | item_value | timestamp 
---------------------------------------------

tbl_categories
-----------------------------
cat_id | item_id | timestamp
-----------------------------

tbl_items中有大约600,000行。我正在使用这个SQL查询:

SELECT e.item_id, e.item_value
  FROM tbl_items AS e
  JOIN tbl_categories AS cat WHERE e.item_id = cat.item_id AND cat.cat_id = 6001
  LIMIT 25

cat_id的循环中使用相同的查询,从6000到6012.但我想要每个类别的最新记录。如果我使用类似的东西:

SELECT e.item_id, e.item_value
  FROM tbl_items AS e
  JOIN tbl_categories AS cat WHERE e.item_id = cat.item_id AND cat.cat_id = 6001
  ORDER BY e.timestamp
  LIMIT 25

..查询计算大约10分钟,这是不可接受的。我可以更好地使用LIMIT来为每个类别提供最新的25条记录吗?

任何人都可以帮助我在没有ORDER BY的情况下实现这一目标吗?任何想法或帮助将受到高度赞赏。

修改

tbl_items

+---------------------+--------------+------+-----+---------+-------+
| Field               | Type         | Null | Key | Default | Extra |
+---------------------+--------------+------+-----+---------+-------+
| item_id             | int(11)      | NO   | PRI | 0       |       |
| item_name           | longtext     | YES  |     | NULL    |       |
| item_value          | longtext     | YES  |     | NULL    |       |
| timestamp           | datetime     | YES  |     | NULL    |       |
+---------------------+--------------+------+-----+---------+-------+

tbl_categories

+----------------+------------+------+-----+---------+-------+
| Field          | Type       | Null | Key | Default | Extra |
+----------------+------------+------+-----+---------+-------+
| cat_id         | int(11)    | NO   | PRI | 0       |       |
| item_id        | int(11)    | NO   | PRI | 0       |       |
| timestamp      | datetime   | YES  |     | NULL    |       |
+----------------+------------+------+-----+---------+-------+

3 个答案:

答案 0 :(得分:1)

你能添加指数吗?如果您在timestamp和其他相应列上添加索引,ORDER BY将不会花费10分钟。

答案 1 :(得分:1)

首先:

似乎是itemscategories之间的N:M关系:item可能在几个categories中。我这样说是因为categoriesitem_id个外键。

如果不是N:M关系,那么你应该考虑改变设计。如果它是1:N关系,其中类别包含多个项目,则item必须保留category_id个外键。

使用N:M:

我已经重写了你的查询以使内部联接成为交叉联接:

  SELECT e.item_id, e.item_value
  FROM 
     tbl_items AS e
  JOIN 
     tbl_categories AS cat 
        on e.item_id = cat.item_id
  WHERE  
     cat.cat_id = 6001
  ORDER BY 
     e.timestamp
  LIMIT 25

要优化所需的性能索引是:

create index idx_1 on tbl_categories( cat_id, item_id)

它不是必需的项目索引,因为主键也被索引。 包含时间戳的索引没有帮助作为mutch。确保可以尝试使用item_idtimestamp的项目的索引来避免访问表并从索引中获取值:

create index idx_2 on tbl_items( item_id, timestamp)

要提高性能,您可以通过单个查询更改类别循环:

  select T.cat_id, T.item_id, T.item_value from 
  (SELECT cat.cat_id, e.item_id, e.item_value
   FROM 
     tbl_items AS e
   JOIN 
     tbl_categories AS cat 
        on e.item_id = cat.item_id
   ORDER BY 
     e.timestamp
   LIMIT 25
  ) T
  WHERE  
     T.cat_id between 6001 and 6012
  ORDER BY
     T.cat_id, T.item_id

请尝试此查询,并在必要时回复您的评论以进行优化。

答案 2 :(得分:1)

除了所有其他因素外,我可以告诉您查询速度太慢的主要原因是因为结果涉及longtext列。

MySQL中的

BLOBTEXT字段主要用于存储完整的文件,文本或二进制文件。它们与InnoDB表的行数据分开存储。每次查询involes排序(显式或group by)时,MySQL肯定会使用磁盘进行排序(因为它无法提前确定任何文件的大小)。

这可能是一条经验法则:如果您需要在查询中返回多行的一行,那么该字段的类型几乎不应该是TEXTBLOB ,请改用VARCHARVARBINARY

<强> UPD

如果无法更新表,则使用当前索引和列类型的查询几乎不会很快。但是,无论如何,这是一个类似的问题,也是您问题的流行解决方案:How to SELECT the newest four items per category?