2012-01-17 87 views
1

我在写一个脚本,它将列出所有12个类别中的25个项目。数据库结构如下:SQL LIMIT获取最新记录

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

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

表中有大约600,000行tbl_items。我使用这个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到6012上的环从6000相同的查询,但我想每个类别的最新记录。如果我使用类似的东西:

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 |  | 
+----------------+------------+------+-----+---------+-------+ 
+0

请显示您的表创建语句。你的索引是否正确? – 2012-01-17 07:59:55

+0

我编辑了这个问题。 – Astha 2012-01-17 08:10:19

+1

@Astha - 请你确认你有什么索引,以及你是否可以请求/创建新索引? – MatBailie 2012-01-17 09:45:18

回答

1

首先:

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

如果不是N:M关系,那么您应该考虑更改设计。如果它是1:N关系,那么类别有几个项目,那么item必须包含category_id外键。 L::

与N个工作

我重写查询,以使内连接insteat交叉联接:

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) 

它不是强制项目的索引,因为主键也被索引。 包含时间戳的索引不会帮助您进行转换。为了确保能对项目指标与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 

请试试这个查询并回来与您的意见,如有必要改进它。

+0

感谢您的回复。我不能改变数据库的结构,因为它不是我的。但是,它是1:N关系表。一个item_id将只在一个类别中。我试过这个查询,但它也花费了相同的时间。我正在使用一个循环的类别标识一个我不能像这样使用单一查询与caluse之间。希望你明白我的观点。 – Astha 2012-01-17 09:41:44

+1

如果不是您的数据库,它们不是一个简单的解决方案。看看这个相关的问题:[是否可以跨表索引?](http://stackoverflow.com/questions/8509026/is-cross-table-indexing-possible) – danihp 2012-01-17 09:54:40

1

你可以添加索引?如果您在timestamp和其他适当的列上添加索引,ORDER BY将不需要10分钟。

+0

感谢您的回复,但什么样的索引?请解释? – Astha 2012-01-17 08:01:02

+0

索引就像电话簿。如果电话簿中没有订单,则需要几个小时才能查找某人的电话号码。时间戳列上的一个索引告诉MySQL记录所在的位置,*通过时间戳*,因此它可以像查找电话簿一样查找行。 – toon81 2012-01-17 08:06:03

+0

不幸的是,我不知道有什么像样的网站能让你开始。 (任何人?) – toon81 2012-01-17 08:06:44

1

撇开所有其他因素,我可以告诉你,查询速度如此之慢的主要原因是因为结果涉及到longtext列。

BLOBTEXT MySQL中的字段主要用于存储完整的文件,文本或二进制文件。它们与InnoDB表的行数据分开存储。每次查询调用排序(显式或为group by)时,MySQL肯定会使用磁盘进行排序(因为事先不能确定文件有多大)。

,它可能是一个经验法则:如果你需要比在查询中的列单行返回越多,字段的类型几乎都不应该是TEXTBLOB,使用VARCHARVARBINARY代替。

UPD

如果不能更新表,查询将难以快速与当前索引和列类型。但是,无论如何,这里是一个类似的问题和一个流行的解决方案,以您的问题:How to SELECT the newest four items per category?

+0

感谢您的解释。真的很感激,但正如我告诉这个数据库不是我的。我只需要取数据来显示。 – Astha 2012-01-18 03:59:54

+0

@astha,我更新了我的答案。 – newtover 2012-01-18 08:27:12

+0

非常感谢您的帮助! – Astha 2012-01-18 09:44:04