1

非常によく似た 2 つのクエリがあります。次のように、同じ 4 つのテーブルで動作します。

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

基本的に、クエリは test、users_old、および users_new に対して実行され、test_attempts に挿入されます。

これは最初のクエリです。実行には約 1 分かかります。これは長いですが、深刻な問題ではありません。その主要なWHERE句には句が含まれています:tests.overall_score IS NOT NULL ANDこれは、このクエリの 2 番目のバージョンで後で変更されます。

# 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);

これは 2 番目のクエリです。実行には約 10 分かかり、時間がかかります。その主要な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最初のクエリから を削除すると、操作時間が 10 倍になる理由がわかりません。この時間差が発生する理由を理解するまで、実稼働環境でこれを実行することはできません。MyISAM テーブルはテーブル ロックを使用しているため、これによりサイトが 10 分間ロックダウンされ、実際にはオプションではありません。今回の不一致が発生している理由がわからないので、洞察があれば役立ちます。ありがとうございました。

4

1 に答える 1

1

where 句に 'is not null' 修飾子を追加すると、完全なテーブル スキャンが実行されます。説明計画はこれを指摘する必要があります。全体のスコア列に「まだスコアがない」ことを示す「デフォルト」値 (0 または -1 など) を設定し、この列にインデックスを追加し、where 句を「= 0」を示すように変更すると、クエリは次のようになります。テーブルスキャンなしで一致する行のみを処理できます。

于 2013-08-06T05:14:08.483 に答える