mysql优化 - 显示10条最新记录,但也标识重复行

时间:2010-02-03 06:28:32

标签: mysql optimization group-by sql-order-by

我是mysql的新手,几天来我一直在解决这个问题。我需要改进/优化这个查询,以便它运行得更快 - 现在它需要超过5秒。

以下是查询:

SELECT SQL_NO_CACHE COUNT(*) as multiple, a.*,b.*  
FROM announcements as a  
INNER JOIN stores as s  
ON a.username=s.username
    WHERE s.username is not null AND s.state='NC' 
GROUP BY a.announcement_id
ORDER BY a.dt DESC LIMIT 0,10

商店表包含:store_id,用户名,名称,州,城市,邮编等......

公告表包含:announcement_id,msg,dt,username

stores表有大约10,000条记录,公告表有大约500,000条记录。

我正在尝试用英语完成 - 显示最近的10个商店公告但是这使得复杂的是商店可以在商店表中具有多个具有相同用户ID的条目(每个位置一行)。因此,如果连锁店,让我们说“Chipotle”发送公告,我想只显示一行他们的公告,旁边有一个说明“这个商店有多个位置”。这就是为什么我使用count(*)和group by,所以如果count(*) > 1我知道公告有多个位置。

where条件可以是任何州,城市或邮编。使用SQL_NO_CACHE是因为公告经常更新,所以你很少得到相同的结果,这有意义吗?

我真的很感激有关如何做得更好的任何建议。我对索引知之甚少,但我确实为两个表中的“用户名”字段创建了一个索引。请随意把我分开,我知道我一定会错过一些东西。

更新 -

DESC商店;

Field       Type            Null    Key     Default         Extra  
store_id    int(11)         NO      PRI     NULL            auto_increment  
username    varchar(20)     NO      MUL     NULL       
name        varchar(100)    NO              NULL       
street      varchar(100)    NO              NULL       
city        varchar(50)     NO              NULL       
state       varchar(2)      NO              NULL       
zip         varchar(15)     NO              NULL      

DESC公告;

Field              Type           Null      Key     Default     Extra
dt                 datetime       NO                NULL     
username           varchar(20)    NO        MUL     NULL     
msg                varchar(200)   NO                NULL     
announcement_id    int(11)        NO        PRI     NULL        auto_increment

EXPLAIN输出;

id  select_type     table   type    possible_keys   key       key_len     ref         rows     Extra
1   SIMPLE          a       index   username        PRIMARY   47          NULL        315001   Using temporary; Using filesort
1   SIMPLE          b       ref     username        username  62          a.username  1        Using where

3 个答案:

答案 0 :(得分:2)

尝试这样的事情:

SELECT SQL_NO_CACHE COUNT(*) as multiple, a.*,b.*   
FROM announcements as a   
INNER JOIN 
(
  SELECT username, COUNT(username) as multiple FROM stores
  WHERE username IS NOT NULL AND state = 'NC'
  GROUP BY username
 )  as s 
ON a.username=s.username 
ORDER BY a.dt DESC LIMIT 10 

答案 1 :(得分:0)

如果您在dt列上订购,但该列上没有索引,那么每次运行查询时,MySQL都必须对该列上的所有结果行进行(缓慢,昂贵)排序< / p>

尝试在announcements.dt上添加索引 - MySQL可以使用索引按顺序访问行,并在之后避免排序步骤。

答案 2 :(得分:0)

  • 更改JOIN中表的顺序,MySQL从第一个表中读取行然后 在第二个表中查找匹配的行。如果总是按照stores表中的字段过滤结果,那么stores表应该是JOIN中的前导表,因此它不会从公告表中挑选和排序不必要的行。
    在您粘贴的EXPLAIN输出中,似乎只有一个商店与查询匹配,切换表的顺序会导致它只在通知表中查找该特定商店。
  • 在dt列上添加索引(使用带有unixtime的索引整数列会更好)
  • 如果可能的话 - 使用该列为每个用户名和JOIN创建一个整数userID(在该列上添加一个on索引)
  • 不确定MySQL是否仍有问题,但用COUNT(1)替换COUNT(*)可能会有所帮助。