【问题标题】:Mysql performance on 6 million row tableMysql 在 600 万行表上的性能
【发布时间】:2010-11-10 00:29:25
【问题描述】:

有一天我怀疑我必须学习 hadoop 并将所有这些数据转移到一个非结构化数据库中,但我惊讶地发现性能在如此短的时间内如此显着下降。

我有一个不到 600 万行的 mysql 表。 我在这张表上做了一个非常简单的查询,并且相信我有所有正确的索引。

查询是

从事件中选择日期、时间,其中 venid='47975' AND date>='2009-07-11' ORDER BY date

解释返回

id select_type table type possible_keys key key_len ref rows Extra 1 简单更新显示范围 date_idx date_idx 7 NULL 648997 使用 where

所以据我所知,我使用的是正确的索引,但是这个查询需要 11 秒才能运行。

数据库是MyISAM,phpMyAdmin说表是1.0GiB。

这里有什么想法吗?

编辑: date_idx 是 date 和 venid 列的索引。那应该是两个单独的索引吗?

【问题讨论】:

  • 您的解释查询说它必须扫描 648997 行(可能它没有足够有效地使用索引。如果是我,我会单独索引列)。实际返回了多少行?

标签: mysql performance indexing


【解决方案1】:

您要确保查询将仅使用索引,因此请确保索引涵盖您选择的所有字段。此外,由于它涉及范围查询,因此您需要将 venid 首先放在索引中,因为它是作为常量查询的。因此,我会像这样创建和索引:

ALTER TABLE events ADD INDEX indexNameHere (venid, date, time);

有了这个索引,完成查询所需的所有信息都在索引中。这意味着,希望存储引擎能够获取信息,而无需实际在表本身内部进行搜索。但是,MyISAM 可能无法做到这一点,因为它不会将数据存储在索引的叶子中,因此您可能无法获得所需的速度提升。如果是这种情况,请尝试创建表的副本,并在副本上使用 InnoDB 引擎。在那里重复相同的步骤,看看你是否能显着提高速度。 InnoDB 确实将字段值存储在索引叶子中,并允许覆盖索引。

现在,希望您在解释查询时会看到以下内容:

mysql> EXPLAIN SELECT date, time FROM events WHERE venid='47975' AND date>='2009-07-11' ORDER BY date;

id  select_type table  type  possible_keys        key       [..]  Extra
1   SIMPLE   events range date_idx, indexNameHere indexNameHere   Using index, Using where

【讨论】:

  • +1:覆盖索引是必不可少的。有了仔细的索引和仔细的查询,6 毫米的行也没什么大不了的。
  • 太棒了!谢谢。我没有意识到我需要用索引覆盖 SELECTED 字段。我以为只是需要索引的 WHERE 字段。
  • 如果你还记得,新查询的索引执行时间是多少?
  • @pedalpete 我问和贾斯汀一样的问题。
  • 抱歉@JustinKrause(和其他人)回复晚了,您的评论确实是在最初的问题之后几年出现的。修复索引后,我相信查询时间不到 0.4 秒。它的速度令人惊讶,而且它也不是在专用服务器上。它是一个中等大小的托管盒子,当时并不算大。我不记得是 linode 还是不久之后我切换到了 linode。
【解决方案2】:

尝试添加一个跨越 venid 和 date 的密钥(或相反,或两者兼而有之......)

【讨论】:

  • 当您说“添加键”时,您是指索引吗?我编辑了我的条目以声明 date_idx 在 date 和 venid 字段上。
  • 谢谢迈克尔,我没有意识到 SELECT 字段也应该被索引。干杯。
  • 索引上没有 SELECT 字段会使系统更加僵化。任何新的预测都必须添加到索引中。这是正确的做法吗?
【解决方案3】:

我想一个 6M 的行表应该可以用非常普通的技术进行优化。

我假设你有一个专用的数据库服务器,并且它有一个合理的内存量(比如至少 8G)。

您需要确保已调整 mysql 以有效地使用您的 ram。如果您运行的是 32 位操作系统,请不要这样做。如果您使用的是 MyISAM,请调整您的密钥缓冲区以使用显着比例的内存,但不要太多。

在任何情况下,您都希望在生产级硬件上运行重复的性能测试。

【讨论】:

  • 感谢@MarkR,很抱歉很晚才回复。这是我建立的第二个网站,所以不知道专用的数据库服务器或类似的东西。我用同一个盒子上的所有进程运行了几年。没问题,我很惊讶 MySQL 扩展到 800 万行以上。当它达到那个点时,我会归档旧数据。
【解决方案4】:

尝试在venid 列上放置索引。

【讨论】:

  • 我刚刚编辑了我的条目,date_idx 在 date 和 venid 字段上。对不起,我最初没有把它放进去。
猜你喜欢
  • 1970-01-01
  • 2012-07-27
  • 2012-07-10
  • 2010-12-11
  • 2021-07-23
  • 1970-01-01
  • 1970-01-01
  • 2020-11-23
  • 2016-05-02
相关资源
最近更新 更多