0

これはMySQL5.5を使用しています。MySQLにこれらのクエリにインデックスを使用するように説得することはできないようで、110万行のテーブルで実行するのに2〜10秒かかります。

テーブル:

CREATE TABLE `notifiable_events` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`key` varchar(255) NOT NULL,
`trigger_profile_id` int(10) unsigned DEFAULT NULL,
`model1` varchar(25) NOT NULL,
`model1_id` varchar(36) NOT NULL,
`model2` varchar(25) NOT NULL DEFAULT '',
`model2_id` varchar(36) NOT NULL DEFAULT '',
`event_data` text,
`created` datetime DEFAULT NULL,
`modified` datetime DEFAULT NULL,
`deleted` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `key` (`key`),
KEY `notifiable_events__trigger_profile` (`trigger_profile_id`),
KEY `deleted` (`deleted`),
KEY `noti_evnts__m2` (`model2`),
KEY `noti_evnts__m1` (`model1`),
CONSTRAINT `notifiable_events__trigger_profile` FOREIGN KEY (`trigger_profile_id`) REFERENCES `profiles` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1177918 DEFAULT CHARSET=utf8

質問:

  SELECT * 
    FROM notifiable_events 
    WHERE (`model1` = 'page' AND `model1_id` = '54321') 
       OR (`model2` = 'page' AND `model2_id` = '12345');

説明:

mysql> EXPLAIN EXTENDED SELECT * FROM notizable_events WHERE( `model1` ='page' AND` model1_id` = '922645')OR( `model2` ='page' AND` model2_id` = '922645')\ G

    ***************************1.行******************** *******
               id:1
      select_type:SIMPLE
            テーブル:notizable_events
             タイプ:ALL
    possible_keys:noti_evnts__m2、noti_evnts__m1、noti_evnts__m1_m2
              キー:NULL
          key_len:NULL
              ref:NULL
             行:1033088
         フィルタリング:100.00
            追加:どこで使用するか
    セット内の1行、1つの警告(0.00秒)

mysql> EXPLAIN EXTENDED SELECT * FROM notizable_events WHERE( `model1` ='page' AND` model1_id` = '922645')OR( `model1` ='page' AND` model1_id` = '922645')\ G
***************************1.行******************** *******
           id:1
  select_type:SIMPLE
        テーブル:notizable_events
         タイプ:ref
possible_keys:noti_evnts__m1、noti_evnts__m1_m2
          キー:noti_evnts__m1
      key_len:77
          ref:const
         行:1
     フィルタリング:100.00
        追加:どこで使用するか
セット内の1行、1つの警告(0.00秒)

mysql> EXPLAIN EXTENDED SELECT * FROM notizable_events WHERE( `model2` ='page' AND` model2_id` = '922645')OR( `model2` ='page' AND` model2_id` = '922645')\ G
***************************1.行******************** *******
           id:1
  select_type:SIMPLE
        テーブル:notizable_events
         タイプ:ref
possible_keys:noti_evnts__m2
          キー:noti_evnts__m2
      key_len:77
          ref:const
         行:428920
     フィルタリング:100.00
        追加:どこで使用するか
セット内の1行、1つの警告(0.00秒)

model1のみまたはmodel2のみを使用すると、インデックスが使用されることがわかりますが、両方を一緒に使用しようとすると、インデックスが完全に放棄され、全表スキャンが実行されます。私はすでにFORCEINDEXを試し、マルチキーインデックスの組み合わせを試しました(例として、このテーブル用に1つ残しました)。また、クエリ内の要素の順序を並べ替えてみましたが、効果がないようです。

更新:私はすでにANALYZEとOPTIMIZEを試したことを忘れました(それぞれ複数回、変更なし)。また、* _ idのインデックス(カーディナリティは非常に悪く、これらの列はほとんどが一意のエントリです)と、クエリで4つの列すべてが使用されているマルチインデックスも試しました。どちらの場合も、インデックスの改善や使用はありません。

ここでチェックする行を制限するためにインデックスを使用するのは本当に簡単なはずなので、何かが足りないことを願っています。

4

1 に答える 1

4

or句は、クエリの最適化に失敗することがあります。

このようなユニオンを試すことができます。インデックスが再アクティブ化される場合があります。

SELECT * 
  FROM notifiable_events 
 WHERE  `model1` = 'page' AND `model1_id` = '54321'
 UNION
SELECT * 
  FROM notifiable_events 
 WHERE `model2` = 'page' AND `model2_id` = '12345'

編集、コメントの質問に答える

この種の選択スキームを使用してレコードを更新しようとしている場合は、これを試すことができます。

UPDATE notifiable_events
   SET what=ever,
       what=ever,
       what=else 
 WHERE id IN (
   SELECT id 
     FROM notifiable_events 
    WHERE  `model1` = 'page' AND `model1_id` = '54321'
    UNION
   SELECT id 
     FROM notifiable_events 
    WHERE `model2` = 'page' AND `model2_id` = '12345'
 )

(実際に何をしようとしているのかを説明するために Stackoverflow を使用している場合に役立つことに注意してください。もちろん、複雑な問題を単純なものに減らすことはできれば問題ありません。 '実際に UPDATE を行っているのは、うーん、単純化しすぎです。)

于 2012-07-12T01:52:23.573 に答える