【问题标题】:mysql optimization - display 10 most recent records, but also identify duplicate rowsmysql优化——显示最近的10条记录,同时也识别重复行
【发布时间】:2010-02-07 15:19:07
【问题描述】:

我是 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

Stores 表包括:store_id、username、name、state、city、zip 等...

Announcements表包括:announcement_id, msg, dt, username

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

我想要用英语完成的工作 - 显示 10 个最近的商店公告,但让事情变得复杂的是,商店可以在 stores 表中具有相同用户 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

解释输出;

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

【问题讨论】:

  • @Art: 可以添加当前查询的解释输出吗,它可以帮助数据库专家知道您需要什么样的索引
  • 请发布包含索引的完整表格规范(例如使用DESC mytable)。
  • @RageZ @Max S 更新了您要求的信息
  • 我认为“order by”是真正减慢速度的原因——当我把这部分拿出来时,它运行得非常快。有什么办法可以避免对所有行进行文件排序?

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


【解决方案1】:

试试这样的:

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 

【讨论】:

  • 我认为您的意思是 SELECT multiple 而不是 COUNT(*) 在外部查询中,不是吗?
  • 还要选择s.*,而不是b.*,因为查询中没有表别名b
  • 谢谢,这肯定更快。
【解决方案2】:

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

尝试在announcements.dt 上添加索引——MySQL 或许能够通过使用索引来按顺序访问行,并避免之后的排序步骤。

【讨论】:

    【解决方案3】:
    • 更改 JOIN 中表的顺序,MySQL 从第一个表中读取行,然后 在第二个表中查找匹配的行。如果您始终按 stores 表中的字段过滤结果,则 stores 表应该是 JOIN 中的前导表,因此它不会从公告表中挑选和排序不必要的行。
      在您粘贴的 EXPLAIN 输出中,似乎只有一家商店与查询匹配,切换表的顺序将导致它仅在公告表中查找该特定商店。
    • 在 dt 列上添加索引(使用 unixtime 索引整数列会更好)
    • 如果可能 - 为每个用户名创建一个整数用户 ID,并使用该列加入(也为该列添加一个 on 索引)
    • 不确定 MySQL 是否仍然存在此问题,但将 COUNT(*) 替换为 COUNT(1) 可能会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-14
      • 1970-01-01
      • 2015-11-07
      • 2019-12-28
      • 2015-03-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多