1

MySQL InnoDB オプティマイザーでリクエストを最適化するのに問題があります。次のクエリ (クエリ 1) は効率的に実行されます。

explain select * from ah_problems
where rnid in (6022342, 6256614, 5842714, 6302489)
and fieldid in (5,6);

計画(計画1)は次のとおりです。

id select_type table       type  possible_keys                   key           key_len ref rows Extra
=  ======      =========== ===== =============================== ============= ======= === ==== =====
1  SIMPLE      ah_problems range CONSTRAINTFIELDID,RNID__FIELDID RNID__FIELDID 8           33   Using where

ここまでは順調ですね。

一方、以下のわずかに変更されたクエリ (クエリ 2) は壊滅的な実行計画を取ります。

explain select * from ah_problems
where rnid in (select rec.rnid as record_id from ar_records rec where rnid in (6022342, 6256614, 5842714, 6302489))
and fieldid in (5, 6)

結果は同じですが、プラン (プラン 2) は次のようになります。

id select_type        table       type            possible_keys      key      key_len ref  rows     Extra
=  ======             =========== =====           ================== ======== ======= ==== =======  =====
1  PRIMARY            ah_problems ALL             CONSTRAINTFIELDID                        36177754 Using where
2  DEPENDENT SUBQUERY rec         unique_subquery PRIMARY            PRIMARY  4       func 1        Using index; Using where

不思議に思うなら、その新しいサブクエリは...

select rec.rnid as record_id from ar_records rec where rnid in (6022342, 6256614, 5842714, 6302489)

...クエリ 1 でハードコーディングされた 4 つの行を返すだけです。

6022342
6256614
5842714
6302489

したがって、クエリ (1) と (2) は同等です。

1 つではなく、クエリ 2 が必要だと思います。そして、クエリ 2 をクエリ 1 と同じくらい効率的にしたいのですが、次のことを試しました。

  1. クエリ 3: クエリ 2 に追加FORCE INDEX(RNID_FIELDID)します。MySQL は単純に無視します。

    説明 select * from ah_problems force index (rnid__fieldid) where rnid in (select rec.rnid as record_id from ar_records rec where rnid in (6022342, 6256614, 5842714, 6302489)) and fieldid in (5,6)

実行計画は計画 2 と同じです。

  1. クエリ 4: クエリ 3 に an を追加ORDER BY RNID, FIELDIDします。他のいくつかの質問で、これがオプティマイザをだます可能性があることがわかりました。役に立ちません。

    説明 select * from ah_problems force index (rnid__fieldid) where rnid in (select rec.rnid as record_id from ar_records rec where rnid in (6022342, 6256614, 5842714, 6302489)) と fieldid in (5, 6) 順 rnid, fieldid

プラン 4 は現在インデックスを使用していますが、行数は依然として壊滅的です。

id select_type        table       type            possible_keys      key           key_len ref  rows      Extra
=  ======             =========== =====           ================== ========      ======= ==== =======   =====
1  PRIMARY            ah_problems index                              RNID__FIELDID 8             36179307 Using where
2  DEPENDENT SUBQUERY rec         unique_subquery PRIMARY            PRIMARY       4       func  1        Using index; Using where

これが役立つ場合、これが私のah_problemsテーブルの定義です。残念ながら、テーブルの定義を変更することはできません。MySQL オプティマイザーがプラン 1 を使用ah_problemsしてクエリ 2 のテーブルを攻撃するようにするためにできることはありますか?

CREATE TABLE `ah_problems` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Identifier for update statements',
  `RNID` int(11) NOT NULL COMMENT 'Record number',
  `FIELDID` int(11) NOT NULL COMMENT 'Which field is value in',
  `VALUE` varchar(255) NOT NULL COMMENT 'The value the field got on MODIFIED_DATE',
  `PREVIOUSID` int(11) DEFAULT NULL COMMENT 'Reference to previous value',
  `MODIFIED_DATE` datetime NOT NULL COMMENT 'When was it changed',
  `MODIFIED_GROUPID` int(11) DEFAULT NULL COMMENT 'In what group did modified_userid change it',
  `MODIFIED_USERID` int(11) NOT NULL COMMENT 'Who changed it',
  PRIMARY KEY (`ID`),
  KEY `CONSTRAINTFIELDID` (`FIELDID`),
  KEY `CONSTRAINTMODIFIED_GROUPID` (`MODIFIED_GROUPID`),
  KEY `CONSTRAINTMODIFIED_USERID` (`MODIFIED_USERID`),
  KEY `CONSTRAINTPREVIOUSID` (`PREVIOUSID`),
  KEY `RNID__FIELDID` (`RNID`,`FIELDID`),
  CONSTRAINT `HPRB_FIELD` FOREIGN KEY (`FIELDID`) REFERENCES `ad_fields` (`ID`),
  CONSTRAINT `HPRB_MODIFIED_GROUP` FOREIGN KEY (`MODIFIED_GROUPID`) REFERENCES `ap_groups` (`ID`),
  CONSTRAINT `HPRB_MODIFIED_USER` FOREIGN KEY (`MODIFIED_USERID`) REFERENCES `ap_users` (`ID`),
  CONSTRAINT `HPRB_PREVIOUS` FOREIGN KEY (`PREVIOUSID`) REFERENCES `ah_problems` (`ID`) ON DELETE CASCADE,
  CONSTRAINT `HPRB_RN` FOREIGN KEY (`RNID`) REFERENCES `ar_records` (`RNID`)
) ENGINE=InnoDB AUTO_INCREMENT=72305308 DEFAULT CHARSET=utf8 COMMENT='PTR history'$$
4

2 に答える 2

1

MySQLWHERE fieldid IN (5, 6)はサブクエリの前に解決する必要があると思います。次のインデックスを追加してみてください。

ALTER TABLE ah_problems ADD INDEX FIELDID__RNID (FIELDID, RNID);

問題が解決しない場合は、クエリを次のように書き直してくださいJOIN

SELECT *
FROM ah_problems
JOIN ar_records USING (rnid)
WHERE rnid in (6022342, 6256614, 5842714, 6302489)
AND fieldid in (5, 6)
于 2013-04-30T16:47:48.603 に答える
1

MySQLINサブクエリを先行するように最適化することはできません(1 回だけ実行されます)。ループ内のメインクエリの各レコードに対して常に実行されます。

結合に置き換えます。

SELECT ahp.*
FROM   ar_records ar
JOIN   ah_problems ahp
ON     ahp.rnid = ar.rnid
       AND ahp.fieldId IN (5, 6)
WHERE  ar.rnid IN (6022342, 6256614, 5842714, 6302489)
于 2013-04-30T16:46:07.310 に答える