NULL和NOT NULL版本的查询之间的时间增加了10倍

时间:2013-07-22 18:07:26

标签: mysql insert innodb myisam

我有两个非常相似的查询。它们在相同的四个表上工作,如下所示:

users_old      => MyISAM 
users_new      => InnoDB
test_attempts  => InnoDB
tests          => MyISAM

基本上,在test,users_old和users_new上运行查询,该查询将插入test_attempts。

这是第一个查询,运行大约需要一分钟,这很长,但不是一个严重的问题。其主WHERE子句包含子句:tests.overall_score IS NOT NULL AND,稍后在此查询的第二个版本中进行了更改:

# this query takes everyone that has taken the wsat-pe legacy and gives them an attempt record
INSERT INTO 
    test_attempts (`user_id`, `test_id`, `score`, `created`, `modified`, `is_deleted`, `meter`, `type`, `status`)   
SELECT 
    users_new.id, 76, tests.overall_score, FROM_UNIXTIME(start_time), FROM_UNIXTIME(end_time), NULL, NULL, 'normal', 'complete' 
FROM 
    users_old, users_new, tests 
WHERE 
    users_old.user_email = users_new.email AND 
    tests.user_id = users_old.id AND 
    users_new.role <> 'admin' AND
    tests.overall_score IS NOT NULL AND
    users_new.id NOT IN (SELECT test_attempts.user_id FROM test_attempts WHERE test_attempts.test_id = 76);

这是第二个查询,运行大约需要十分钟,这很长。其主WHERE子句包含以下子句:tests.overall_score IS NULL AND SELECT标题将'complete'更改为'canceled'但这些是唯一的差异。

# This cancels the attempts that have been droped by users  
INSERT INTO 
   tests_attempts (`user_id`, `test_id`, `score`, `created`, `modified`, `is_deleted`, `meter`, `type`, `status`)
SELECT 
   users_new.id, 76, tests.overall_score, FROM_UNIXTIME(start_time), FROM_UNIXTIME(end_time), NULL, NULL, 'normal', 'canceled' 
FROM 
   users_old, users_new, tests 
WHERE 
    users_old.user_email = users_new.email AND 
    tests.user_id = users_old.id AND
    users_new.role <> 'admin' AND
    tests.overall_score IS NULL AND
    users_new.id NOT IN (SELECT test_attempts.user_id FROM test_attempts WHERE test_attempts.test_id = 76); 

它们一个接一个地在给定的表上运行。我无法理解为什么从第一个查询中删除NOT会导致操作时间增加十倍。在我明白为什么会出现这种时差之前,我无法在生产环境中运行它。由于MyISAM表使用表锁定,这会将我们的站点锁定十分钟,这不是一个真正的选择。我不确定为什么这个时间差异正在发生,所以任何见解都会有所帮助。谢谢。

1 个答案:

答案 0 :(得分:1)

在where子句中添加'is not null'限定条件将导致全表扫描。解释计划应该指出这一点。如果您在总分数列中添加“默认”值以指示“尚未得分”(例如0或-1),并在此列上添加索引并更改您的where子句以指示“= 0”,则您的查询将只能在没有表扫描的情况下处理匹配的行。