我们有一个查询,该查询在本地运行时会快速返回,但是当在我们的登台环境中运行相同的查询时,它会花费很长时间。
本地数据库是阶段数据库的副本(截至上次备份),因此两者应该非常相似。当我运行这个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的“类型”值在舞台上说“索引”,在舞台上说“全部”
有人知道为什么两种环境的结果如此不同吗?
答案 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
)