SQL查询:加快大型表的速度

时间:2015-05-12 08:42:54

标签: mysql sql database performance indexing

我们有一个包含大约25,000,000行的表,称为'events',具有以下模式:

TABLE events
- campaign_id   : int(10)
- city      : varchar(60)
- country_code  : varchar(2)

以下查询需要很长时间(> 2000秒):

SELECT COUNT(*) AS counted_events, country_code
FROM events
WHERE campaign_id` in (597) 
GROUPY BY city, country_code
ORDER BY counted_events

我们发现这是因为GROUP BY部分。

已使用(campaign_id, city, country_code)上的索引idx_campaign_id_city_country_code。

也许有人可以提出一个好的解决方案来加快速度?

更新:

'Explain'表明,在许多可能的索引中,MySql使用这个:'idx_campaign_id_city_country_code',对于它显示的行:'471304'和'Extra'它显示:'使用where;使用临时;使用filesort' -

以下是EXPLAIN的全部结果:

  • id:'1'
  • select_type:'SIMPLE'
  • table:'events'
  • 类型:'ref'
  • possible_keys:'index_campaign,idx_campaignid_paid,idx_city_country_code,idx_city_country_code_campaign_id,idx_cid,idx_campaign_id_city_country_code'
  • key:'idx_campaign_id_city_country_code'
  • key_len:'4'
  • ref:'const'
  • 行:'471304'
  • 额外:'使用地点;使用临时;使用filesort'

更新:

好的,我认为它已经解决了:

再次查看粘贴的查询,我意识到我在这里忘了提到SELECT中还有一个名为'country_name'的列。所以查询非常慢(包括country_name),但我只是把它留下来,现在查询的性能绝对可以。 抱歉,这个错误!

非常感谢您的所有有用的评论,我会提供所有好的答案!有一些非常有用的补充,我可能也应用(比如改变类型等)。

4 个答案:

答案 0 :(得分:3)

没有看到EXPLAIN说它是远距离射击,无论如何:

  1. 在(city,country_code)上建立索引
  2. 看看是否有使用分区的方法,你的桌子变得相当庞大
  3. 如果国家/地区代码始终为2个字符,请将其更改为字符
  4. 将数字索引更改为unsigned int
  5. 发布整个EXPLAIN输出

答案 1 :(得分:0)

不要使用function aktif_kotak(id){ //non_aktif_kotak(); id=id.substr(2, 4); id=parseInt(id)-1; var kotak_aktif=document.getElementById('group-kotak').children[id]; $(kotak_aktif).addClass("kotak-aktif"); $(kotak_aktif).siblings().removeClass("kotak-aktif"); } - 更好地使用:

IN()

afaik WHERE campaign_id = 597 OR campaign_id = 231 OR .... 非常慢。

更新:,例如 nik0lias 已注释 - IN()比连接IN()条件更快。

答案 2 :(得分:0)

一些想法:

  • 鉴于表格的性质和大小,它将成为partitioned tables国家的一个很好的候选人。这样,每个国家的事件都将存储在不同的物理表中,即使它表现为虚拟大表

  • 国家/地区代码是字符串吗?可能你有一个country_id,可以更容易排序。 (它可能会强制您创建或更改索引)

  • 你真的在小组中使用这个城市吗?

答案 3 :(得分:0)

  • 分区 - 特别是按国家/地区帮助
  • 列IN(const-list)不慢,实际上是特殊优化的情况

问题是,MySQL不使用索引进行排序。我不能说为什么,因为它应该。可能是一个错误。

执行此查询的最佳策略是扫描索引的子树,其中event_id = 597。由于索引按city_id排序,因此country_code不需要额外排序,扫描时可以计算行数。

因此索引已经是此查询的最佳选择。 MySQL没有正确使用它们。

我正在离线获取更多信息。看起来这根本不是数据库问题,但是

  1. 架构未规范化。该表不仅包含country_code,还包含country_name(这应该在一个额外的表中)。
  2. 真实查询在选择列表中包含country_name。但由于该列未编入索引,因此MySQL无法使用索引扫描。
  3. 只要从选择列表中删除country_name,查询将恢复为仅索引扫描(在EXPLAIN输出中使用“index”)并且速度非常快。