【问题标题】:Why would this query run so slow?为什么这个查询会运行这么慢?
【发布时间】:2011-10-18 21:27:59
【问题描述】:

我有两个 MySQL 表 A 和 B。A 只包含一个 varchar 列(我们称之为一个 A1),大约有 23000 条记录。表 B(70000 条记录)有更多列,其中一列与表 A 中的 A1 对应(我们称其为 B1)。我想知道A中的哪些值不在B的对应列中,所以我使用:

SELECT A1
FROM A
LEFT JOIN B
    ON A1 = B1
WHERE B1 IS NULL 

A1 和 B1 列都定义了索引。这个查询仍然运行得很慢。我已经运行了解释,这是输出:

id  select_type table   type    possible_keys   key     key_len ref rows    Extra
1   SIMPLE      A       index   \N              PRIMARY 767     \N  23269   Using index
1   SIMPLE      B       ALL     \N              \N      \N      \N  70041   Using where; Not exists

更新:SHOW CREATE TABLE 用于两个表(更改了原始名称);

CREATE TABLE `A` (
  `A1` varchar(255) NOT NULL,
  PRIMARY KEY  (`A1`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8


CREATE TABLE `B` (
  `col1` int(10) unsigned NOT NULL auto_increment,
  `col2` datetime NOT NULL,
  `col3` datetime default NULL,
  `col4` datetime NOT NULL,
  `col5` varchar(30) NOT NULL,
  `col6` int(10) default NULL,
  `col7` int(11) default NULL,
  `col8` varchar(20) NOT NULL,
  `B1` varchar(255) default NULL,
  `col10` tinyint(1) NOT NULL,
  `col11` varchar(255) default NULL,
  PRIMARY KEY  (`col1`),
  KEY `NewIndex1` (`B1`)
) ENGINE=MyISAM AUTO_INCREMENT=70764 DEFAULT CHARSET=latin1

'另一个编辑:data_lengthindex_length 来自SHOW TABLE STATUS

table   data_length index_length
A       465380      435200
B       5177996     1344512

【问题讨论】:

  • 您是否对表格进行任何索引?
  • 有趣的是,如果我“反转”这个,那么做一个 RIGHT JOIN,只有 WHERE A1 IS NULL 它完成得更快
  • 您能否发布个人资料结果:SET profiling=1; SELECT SQL_NO_CACHE A1 FROM A LEFT JOIN B ON A1 = B1 WHERE B1 IS NULL; SHOW PROFILE;... 这可以准确地告诉我们大部分时间都在使用哪个步骤。当我使用示例数据(20000 + 70000 行)测试上述查询时,我在
  • 我现在正在运行它。唯一的问题是我的问题中发布的查询尚未完成.. EDIT;当您测试查询时,您是否使用 varchar 作为列类型?我有一种感觉,这是需要这么长时间的原因之一......
  • @Lex:两个表,每个表都有一个 varchar 列,索引,填充随机字符串,两个表中都存在 4k 个字符串。除了个人资料信息,请张贴这两个表的大约大小...是 MB 还是 GB?这以您无法想象的方式很重要。

标签: mysql sql query-optimization collation


【解决方案1】:

您在 OUTER JOIN 中比较的两列的字符集不同。我不确定这是否是原因,所以我测试并得到了这些结果:

SELECT A1
FROM A
LEFT JOIN B ON A1 = B1
WHERE B1 IS NULL

-- Table A..: 23258 rows, collation = utf8_general_ci
-- Table B..: 70041 rows, collation = latin1_swedish_ci
-- Time ....: I CANCELLED THE QUERY AFTER 20 MINUTES

-- Table A..: 23258 rows, collation = latin1_swedish_ci
-- Table B..: 70041 rows, collation = latin1_swedish_ci
-- Time ....: 0.187 sec

-- Table A..: 23258 rows, collation = utf8_general_ci
-- Table B..: 70041 rows, collation = utf8_general_ci
-- Time ....: 0.344 sec

解决方法:使两个表(或至少两列)的字符集相同。

【讨论】:

  • 是的,这是一个很好的观点。查询中每一行的字符集转换可能需要很长时间。
【解决方案2】:

此查询将扫描表 A 的所有行,但如果您在 B1 上有索引,则很可能不会扫描表 B:

select A1
from A
where not exists (
    select *
    from B
    where B.B1 = A.A1
)

在运行此查询或您的原始查询之前,您可以尝试运行 ANALYZE TABLE 以更新这些表的密钥分布信息:

ANALYZE TABLE A, B

如果这没有帮助,那么您可以尝试使用索引,例如:

select A1
from A ignore index (PRIMARY)
where not exists (
    select *
    from B force index (NewIndex1)
    where B.B1 = A.A1
)

【讨论】:

  • 确实,EXPLAIN 在这个查询上确实显示了两个表的 type=index,但“rows”仍然只显示总行数
  • @Lex 你能给出这些表的完整SHOW CREATE TABLE 输出吗?
  • 我用SHOW CREATE TABLE的输出更新了原始问题
  • @Lex 我已经更新了我的答案。顺便说一句,也许您在这些列中有许多长且相似的值,不是吗?
【解决方案3】:

看来A1B1 都是大片场。

您为 A1B1

创建了索引

确保它们被编入索引!

SELECT A1
FROM A
WHERE A1 NOT IN (
    SELECT B1 AS A1 From B;
)

【讨论】:

  • 嗯...不会破坏原查询的逻辑吗?
  • ?它不会产生相同的结果吗?
  • 这不会产生相同的结果,而且运行速度也很慢(5分钟后还没有完成)
  • 我确定我有索引。您问题中的查询也将比LEFT JOIN 的查询花费更长的时间
【解决方案4】:

如果我使用您的 CREATE TABLES 语句并在您的 SELECT 语句上运行 EXPLAIN,我会得到以下结果:

id  select_type  table  type  possible_keys  key       key_len  ref  rows  Extra  
1   SIMPLE       A      index NULL           PRIMARY   767      NULL 2     Using index 
1   SIMPLE       B      index NULL           NewIndex1 258      NULL 4     Using where; Using index 

在我的 MySQL 版本 (5.1.41) 上,索引按预期使用,所以我认为这可能是 MySQL 中已经修复的错误,假设您的索引设置与您发布的创建表语句中一样。你用的是什么 MySQL 版本?

【讨论】:

    【解决方案5】:

    试试这个查询:

    SELECT B1
    FROM B
    WHERE not B1  in (
      select A1
      from a
    )
    

    【讨论】:

    • 在我有 LEFT JOIN 之前我已经尝试过了,让它运行了几个小时并没有完成......
    • 这肯定更慢。您在发布此答案之前是否运行了 EXPLAIN?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-11
    • 2020-03-19
    • 2014-03-12
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多