【问题标题】:Ten fold time increase between NULL and NOT NULL version of queryNULL 和 NOT NULL 版本的查询之间的时间增加了十倍
【发布时间】:2013-07-22 18:07:25
【问题描述】:

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

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 表使用表锁定,这会将我们的站点锁定十分钟,这不是一个真正的选择。我不确定为什么会出现这种时间差异,因此任何见解都会有所帮助。谢谢。

【问题讨论】:

  • 你不应该在生产环境中使用 MyISAM 表有很多原因,包括你提到的那些。
  • @tadman 是的,但这些表比我早,修复它们是要做的事情的清单。这就是users_new 的一部分。知道这些查询在这里发生了什么吗?我还应该提供一些额外的信息吗?
  • 很难为 MyISAM 和 InnoDB 调整 MySQL 数据库,因为每个引擎都有自己的缓冲区和内存池。如果您只运行 InnoDB,可能会更容易找到解决方案。切换表类型可能有点痛苦,但最终结果是更易于维护系统。一个快速的ALTER TABLE 可以随时将引擎翻转到 InnoDB。
  • SELECT 查询需要多长时间?返回多少条记录?每个查询的执行计划是什么(EXPLAIN SELECT ...)?
  • @RandomSeed 哦,伙计,解释一下,我完全忘记了这一点。好电话。

标签: mysql insert innodb myisam


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-04
    • 1970-01-01
    • 2021-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-16
    相关资源
    最近更新 更多