【问题标题】:Simple MySQL Query Taking 2 to 3 seconds?简单的 MySQL 查询需要 2 到 3 秒?
【发布时间】:2009-08-19 07:10:30
【问题描述】:

我有一个相当简单的进程正在运行,它定期拉取 RSS 提要并更新 MySQL 数据库中的文章。

articles 表现在已填充到大约 130k 行。对于找到的每篇文章,处理器都会检查该文章是否已经存在。这些查询几乎总是需要 300 毫秒,大约每 10 或 20 次尝试,它们需要超过 2 秒。

SELECT id FROM `articles` WHERE (guid = 'http://example.com/feed.rss')  LIMIT 1;
# Query_time: 2.754567  Lock_time: 0.000000  Rows_sent: 0  Rows_examined: 0

我在 guid 列上有一个索引,但是每当遇到新文章时,它就会被添加到文章表中 - 使查询缓存无效(对吗?)。

慢查询日志中的其他一些字段报告检查了 120 多行。

当然,在我的开发机器上,这些查询大约需要 0.2 毫秒。

该服务器是 Engine Yard Solo (EC2) 的虚拟主机,具有 1.7GB 内存和 EC2 目前提供的任何 CPU。

任何建议将不胜感激。

更新

事实证明问题出在椅子和键盘之间。

我在“id”上有一个索引,但正在查询“guid”。

在 'guid' 上添加索引可将查询时间缩短至每次 0.2 毫秒。

感谢大家提供的所有有用提示!

【问题讨论】:

  • 1.7'Mb' 的内存非常小。我的 286 电脑有 1Mb。
  • 是的,请编辑并修复这个数量,因为我看起来和事情“不可能”
  • 修复了内存注释 - 它应该是 GB。谢谢!

标签: mysql performance


【解决方案1】:

运行:

EXPLAIN SELECT id FROM `articles` WHERE (guid = 'http://example.com/feed.rss')  LIMIT 1;

注意前面的EXPLAIN。这会告诉你 MySQL 在做什么。很难相信从索引中探测一行可能需要 2.7 秒,除非您的机器严重超载和/或抖动。考虑到行数为 0,我猜 MySQL 做了一次全表扫描,什么也没找到,这可能意味着你没有你认为的索引。

为了回答您的其他问题,每当您对articles 表进行任何更改时,涉及该表的所有查询缓存条目都将失效。

【讨论】:

    【解决方案2】:

    日志说没有读取甚至检查任何行,因此问题不在于您的查询,而很可能与您的服务器有关。 EC2 的致命弱点是它的 IO/s,也许 MySQL 不得不从磁盘加载索引但服务器的磁盘已经完全饱和了。

    如果您的索引足够小以适合内存(确保您的 my.cnf 为 key_buffer (MyISAM) 或 innodb_buffer_pool_size (InnoDB) 分配足够的内存),您应该能够预加载它使用

    SELECT guid FROM articles
    

    查看说明以确保它显示“使用索引”。如果没有,这个应该:

    SELECT guid FROM articles FORCE INDEX (guid) WHERE LENGTH(guid) > 0
    

    或者,如果guid 不是您的 PRIMARY KEY 或 UNIQUE,您可以删除它的索引并创建另一个索引列,用于以索引大小的一小部分快速检索记录。 guid_crc32 列将是一个 INT UNSIGNED 并且将保存 guid 的 CRC32

    ALTER TABLE articles ADD COLUMN guid_crc32 INT UNSIGNED, ADD INDEX guid_crc32 (guid_crc32);
    UPDATE articles SET guid_crc32 = CRC32(guid);
    

    您的 SELECT 查询将如下所示:

    SELECT id FROM articles WHERE guid = 'http://example.com/feed.rss' AND guid_crc32 = CRC32('http://example.com/feed.rss') LIMIT 1;
    

    优化器应该使用guid_crc32 上的索引,它应该比搜索guid 更快更小。

    【讨论】:

    • 我刚刚注意到 Luke 说一遍又一遍地执行相同的查询最终每几十次尝试就会变慢的部分,这削弱了我关于从磁盘加载索引的理论。除非服务器为索引保留的内存太少以至于每隔几十次尝试就会将其换出。
    【解决方案3】:

    如果这个表被大量更新,那么 mysql 可能无法正确更新索引计数。尝试“检查表文章”以更新索引计数并查看您的表是否正常。

    还尝试查看在您的查询上执行 EXPLAIN 是否在您的开发和生产机器上给出相同的结果。如果结果不同,请尝试 OPTIMIZE TABLE。

    这些是 myisam 还是 innodb 表?

    【讨论】:

      【解决方案4】:

      假设 GUID 已编入索引,并且 ID 是您的主键,则有些“错误”。在这种情况下,它是一个仅索引查询。索引正在从内存中删除,磁盘可能很忙。

      根据您的更新/插入/删除模式,您的数据库可能急需“优化”命令。

      SQL 命令我想查看以下输出:

      show table status like 'articles';
      explain SELECT id FROM `articles` WHERE (guid = 'http://example.com/feed.rss')  LIMIT 1;
      explain articles;
      

      系统命令我想看看(假设是 Linux)的输出:

      iostat 5 5
      

      告诉我们您有多少内存,因为 1.7mb 是错误的,或者正在发生一些真正令人兴奋的事情。

      编辑在 my.cnf 中有多少内存可供 SQL 服务器使用?

      【讨论】:

        猜你喜欢
        • 2021-10-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-28
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多