为什么这些mysql查询在本地和舞台上以不同的方式运行?

时间:2018-12-21 20:09:36

标签: mysql

我们有一个查询,该查询在本地运行时会快速返回,但是当在我们的登台环境中运行相同的查询时,它会花费很长时间。

本地数据库是阶段数据库的副本(截至上次备份),因此两者应该非常相似。当我运行这个explain命令时,我得到的结果非常不同。

EXPLAIN SELECT
    cs_uid
FROM mydb.article
WHERE cs_uid NOT IN (
    SELECT
        articleId
    FROM mydb.article_wordcount
);

本地

id |select_type |table                |partitions |type  |possible_keys |key             |key_len |ref |rows   |filtered |Extra                    |
---|------------|---------------------|-----------|------|--------------|----------------|--------|----|-------|---------|-------------------------|
1  |PRIMARY     |article           |           |index |              |cs_importFileId |5       |    |179869 |100      |Using where; Using index |
2  |SUBQUERY    |article_wordcount |           |index |awc_articleId |awc_articleId   |4       |    |294816 |100      |Using index              |


STAGE

id |select_type |table                |type  |possible_keys |key           |key_len |ref |rows   |Extra       |
---|------------|---------------------|------|--------------|--------------|--------|----|-------|------------|
1  |PRIMARY     |article           |ALL   |              |              |        |    |269910 |Using where |
2  |SUBQUERY    |article_wordcount |index |awc_articleId |awc_articleId |4       |    |295417 |Using index |

mysql的版本相似,但不完全相同:

本地:5.7.24 阶段:5.6.38

我在注释命令中注意到的差异是: *在本地看到“分区”和“过滤”列,但不在舞台上 *本地PRIMARY的“类型”值在舞台上说“索引”,在舞台上说“全部”

有人知道为什么两种环境的结果如此不同吗?

2 个答案:

答案 0 :(得分:0)

差异很可能是由于表的大小。同样,索引的基数可以不同。这两个因素都会影响数据库选择查询计划的方式。

答案 1 :(得分:0)

如果表定义相同,包括相同的索引和相同顺序的列,那么我将把差异放在5.7中的优化器中的差异/改进上。

类似于5.7,Oracle选择使用覆盖索引。在5.6中,它正在访问实际表。


我会避免使用IN (subquery)构造,而应使用 anti-join 模式。这将产生与原始结果几乎相同的结果;最大的区别是,如果子查询返回NULL值,则原始行将不返回任何行。

  EXPLAIN
  SELECT a.cs_uid
    FROM mydb.article a
    LEFT
    JOIN mydb.article_wordcount c
      ON c.articleid = a.cs_uid
   WHERE c.articleid IS NULL

等价于NOT EXISTS的结果; EXPLAIN输出将非常相似

  EXPLAIN
  SELECT a.cs_uid
    FROM mydb.article a
   WHERE NOT EXISTS 
         ( SELECT 1
             FROM mydb.article_wordcount c 
            WHERE c.articleid = a.cs_uid 
         )