0

我已经对这个主题进行了大量搜索/阅读,但我仍然无法找到解决方案。

我有数万行或数十万行的表,总数据量在 300GB 左右。我需要选择的列包含很多 HTML,这可能是问题的一部分。我正在使用压缩。该查询包含两个 WHERE 子句:

 SELECT id, olr_id, COMPRESS(source_html) 
 FROM buildings 
 WHERE scrape_status=1 
 AND parse_status=0 LIMIT 1;

正如人们所预料的那样,id 是一个主键。此外,olr_id 是唯一索引。此查询需要 160-300 秒才能返回结果,这是完全不可行的。奇怪的是(至少对我而言),删除 WHERE 子句以parse_status使查询在 2-3 秒内完成。起初,我想这可能是因为它太具体了,所以我什至尝试删除scrape_status并只运行parse_statusWHERE 子句,但显然正是这个特定的子句导致了执行时间的疯狂增加。

问题是,我不知道对这些列进行索引是否有任何好处(scrape_statusparse_status),因为它们的值范围是 0-2。我想这是我的主要问题——对值差异如此小的列进行索引是否有帮助?我曾经在某处读过,索引确实最适合变化很大的列,但正如我所说,我对想法感到茫然,对于数十万条记录来说,160-300 秒是完全不合理的。

任何输入将不胜感激。如果您需要其他输入来帮助我,我很乐意提供。关于这一点,这些是三个查询中每一个的 EXPLAIN 结果:

id: 1
select_type: SIMPLE
table: building
type: ALL
possible_keys: null
key: null
key_len: null
ref: null
rows: 58664
Extra: Using where

感谢您花时间阅读并提供您可能的任何帮助。

4

2 回答 2

2

WHERE在子句中创建两列的复合索引:

CREATE INDEX ix_sp ON buildings (scrape_status, parse_status);

尽管它们中的每一个本身都不会对表进行太多分区,但组合可能会这样做。

尝试以下方法:

SELECT b1.id, olr_id, COMPRESS(source_html)
from buildings b1
JOIN (SELECT id
      FROM buildings 
      WHERE scrape_status=1 
      AND parse_status=0
      LIMIT 1) b2
USING (id)

您的原始查询可能正在压缩所有匹配的行,即使它们中的大多数都被该LIMIT子句抛出。此版本仅压缩一个选定的行。

于 2013-06-28T19:53:35.953 回答
0

即使索引列没有很多不同的值,索引在您搜索的值不常见的情况下也很有用。换句话说,当搜索更具选择性并匹配一小部分行时,索引会有所帮助。

因此,在这种情况下,创建索引的决定取决于与您的条件匹配的行百分比scrape_status=1parse_status=0. 例如,假设scrape_status=1匹配 2% 的行和parse_status=01% 的行,我想parse_status用作索引的前导列。

如果是这种情况,但几乎所有的行parse_status=0也都有scrape_status=1,那么制作复合索引可能没有什么额外的好处。而如果scrape_status=1在进一步限制匹配行方面是有效的,那么你肯定希望它被内置到索引中。

MySQL 也有针对 LIMIT 的优化。请参阅http://dev.mysql.com/doc/refman/5.6/en/limit-optimization.html 一旦找到所需的匹配行数,它就会尝试退出查询。MySQL 5.6 在这方面增加了一些新的优化。

MYSQL 不会为与 WHERE 子句中的条件不匹配的行计算选择列表表达式。

但是,MySQL确实必须从磁盘读取数据行以根据 WHERE 子句中的条件评估它们。这种 I/O 是大量性能成本的来源,这也是使用索引缩小搜索范围如此重要的原因。如果您的source_html列是包含长字符串的 TEXT 列,这可能会增加 I/O 的额外开销,因为 MySQL 必须从磁盘读取额外的数据页面(有关更多详细信息,请参阅Innodb 中的 Blob 存储)。

于 2013-06-28T20:11:15.790 回答