web-dev-qa-db-ja.com

MySQL実行プランの解釈を支援する

遅いクエリを理解しようとしています。 SELECTは(現時点で)ほぼ18000秒間実行されています(PROCESSLISTのSELECTからの出力)。

           id: 22
         time: 17870
        state: Sending data
left(info,20): SELECT data.object,

それは(私が知る限り)その間ずっとSending data状態で費やされました。

このクエリが何をしているのかを教えてくれるために、EXPLAINで何を見るべきですか?

これがテーブル自体です。最終的には約8700万行あります。

CREATE TABLE `node` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `graph` varchar(100) CHARACTER SET latin1 DEFAULT NULL,
  `subject` varchar(200) NOT NULL,
  `predicate` varchar(200) NOT NULL,
  `object` mediumtext NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `nodeindex` (`graph`(20),`subject`(100),`predicate`(100),`object`(100)),
  KEY `ix_node_subject` (`subject`),
  KEY `ix_node_graph` (`graph`),
  KEY `ix_node_object` (`object`(255)),
  KEY `ix_node_predicate` (`predicate`),
  KEY `node_po` (`predicate`,`object`(130)),
  KEY `node_so` (`subject`,`object`(130)),
  KEY `node_sp` (`subject`,`predicate`(130)),
  FULLTEXT KEY `node_search` (`object`)
) ENGINE=MyISAM AUTO_INCREMENT=473374387 DEFAULT CHARSET=utf8

これが少しサニタイズされたバージョンのクエリです

SELECT data.object, profile.object, profile_name.object, profile_email.object, profile_url.object, profile_username.object
FROM node AS source
JOIN node AS profile ON (source.object = profile.subject)
LEFT JOIN node AS data ON (profile.object = data.subject)
LEFT JOIN node AS profile_name ON (source.object = profile_name.subject AND profile_name.predicate = "name")
LEFT JOIN node AS profile_email ON (source.object = profile_email.subject AND profile_email.predicate = "email")
LEFT JOIN node AS profile_url ON (source.object = profile_url.subject AND profile_url.predicate = "public_url")
LEFT JOIN node AS profile_username ON (source.object = profile_username.subject AND profile_username.predicate = "username")
WHERE source.subject IN ('141819225850615', '150915932479', '178191330369', '191338370463', 
    '589223984441662', '102140504', '103344560', '103565169', '104222894', 
    '106144676', '106946824', '10818722', '108248748', '108979621', 
       ... 50 lines deleted 
    '83569262', '85273841', '85358898', '87037156', '87287360', 
    '88146181', '890372000', '89261234', '89517005', '89784593', 
    '90492894', '90718122', '91220992', '943151972', '943946328', 
    '9460682', '9461422', '94616097', '94633116', '95524371', 
    '95699292', '960546007', '96565646', '97054674', '97196051', 
    '98339494', '99746916') AND
source.predicate IN ("string1", "string2", "string3", "string4") AND
profile.predicate NOT IN ("string1", "string2", "string3", "string4") AND
((MATCH(profile.object) AGAINST("'string6'") 
    OR MATCH(data.object) AGAINST("'string6'")) 
OR (MATCH(profile.object) AGAINST("'string7'") OR MATCH(data.object) AGAINST("'string7'")))

そして、explainextendedの出力は次のとおりです。

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: source
         type: range
possible_keys: ix_node_subject,ix_node_object,ix_node_predicate,node_po,node_so,node_sp,node_search
          key: node_sp
      key_len: 994
          ref: NULL
         rows: 878644
     filtered: 100.00
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: profile
         type: ref
possible_keys: ix_node_subject,ix_node_predicate,node_po,node_so,node_sp
          key: ix_node_subject
      key_len: 602
          ref: sumazi_prdf.source.object
         rows: 11
     filtered: 100.00
        Extra: Using where
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: data
         type: ref
possible_keys: ix_node_subject,node_so,node_sp
          key: ix_node_subject
      key_len: 602
          ref: sumazi_prdf.profile.object
         rows: 11
     filtered: 100.00
        Extra: Using where
*************************** 4. row ***************************
           id: 1
  select_type: SIMPLE
        table: profile_name
         type: ref
possible_keys: ix_node_subject,ix_node_predicate,node_po,node_so,node_sp
          key: node_sp
      key_len: 994
          ref: sumazi_prdf.source.object,const
         rows: 1
     filtered: 100.00
        Extra: 
*************************** 5. row ***************************
           id: 1
  select_type: SIMPLE
        table: profile_email
         type: ref
possible_keys: ix_node_subject,ix_node_predicate,node_po,node_so,node_sp
          key: node_sp
      key_len: 994
          ref: sumazi_prdf.source.object,const
         rows: 1
     filtered: 100.00
        Extra: 
*************************** 6. row ***************************
           id: 1
  select_type: SIMPLE
        table: profile_url
         type: ref
possible_keys: ix_node_subject,ix_node_predicate,node_po,node_so,node_sp
          key: node_sp
      key_len: 994
          ref: sumazi_prdf.source.object,const
         rows: 1
     filtered: 100.00
        Extra: 
*************************** 7. row ***************************
           id: 1
  select_type: SIMPLE
        table: profile_username
         type: ref
possible_keys: ix_node_subject,ix_node_predicate,node_po,node_so,node_sp
          key: node_sp
      key_len: 994
          ref: sumazi_prdf.source.object,const
         rows: 1
     filtered: 100.00
        Extra: 
7 rows in set, 1 warning (1.34 sec)
1
Charlie Martin

sending data出力のSHOW FULL PROCESSLISTは、インデックスの不良または未使用のインデックスを示している可能性が高く、explain出力のextra列のwhereの使用もこれを示しています。

範囲スキャンタイプに基づいて、MYDおよびMYIファイルでランダムディスクI/Oルックアップを大量に実行する必要があるようです。explain出力のrefはこれを示している可能性があります。

以下のクエリからの出力を提供できますか>また、メーカーやモデルなどのハードディスクに関する基本情報や、MysQLのバージョン番号も提供できますか?

SET PROFILING = 1;

SELECT data.object, profile.object, profile_name.object, profile_email.object, profile_url.object, profile_username.object
FROM node AS source
JOIN node AS profile ON (source.object = profile.subject)
LEFT JOIN node AS data ON (profile.object = data.subject)
LEFT JOIN node AS profile_name ON (source.object = profile_name.subject AND profile_name.predicate = "name")
LEFT JOIN node AS profile_email ON (source.object = profile_email.subject AND profile_email.predicate = "email")
LEFT JOIN node AS profile_url ON (source.object = profile_url.subject AND profile_url.predicate = "public_url")
LEFT JOIN node AS profile_username ON (source.object = profile_username.subject AND profile_username.predicate = "username")
WHERE source.subject IN ('141819225850615', '150915932479', '178191330369', '191338370463', 
    '589223984441662', '102140504', '103344560', '103565169', '104222894', 
    '106144676', '106946824', '10818722', '108248748', '108979621', 
       ... 50 lines deleted 
    '83569262', '85273841', '85358898', '87037156', '87287360', 
    '88146181', '890372000', '89261234', '89517005', '89784593', 
    '90492894', '90718122', '91220992', '943151972', '943946328', 
    '9460682', '9461422', '94616097', '94633116', '95524371', 
    '95699292', '960546007', '96565646', '97054674', '97196051', 
    '98339494', '99746916') AND
source.predicate IN ("string1", "string2", "string3", "string4") AND
profile.predicate NOT IN ("string1", "string2", "string3", "string4") AND
((MATCH(profile.object) AGAINST("'string6'") 
    OR MATCH(data.object) AGAINST("'string6'")) 
OR (MATCH(profile.object) AGAINST("'string7'") OR MATCH(data.object) AGAINST("'string7'")))

SHOW PROFILES; 

SHOW PROFILE ALL FOR QUERY [query_id from show profile your select query]

:createtableステートメントにobject mediumtext NOT NULLも表示されます!クエリ内でTEXTデータ型が使用されている場合、MySQLは常にMyISAMディスクベースの一時テーブルを作成しているという事実をご存知ですか。これは、メモリエンジンがTEXTデータ型を格納できないためです。

1
Raymond Nijland