EXPLAINを䜿甚したす。 ク゚リの改善

ク゚リを実行するず、MySQLク゚リオプティマむザヌはこのク゚リに最適なプランを芋぀けようずしたす。 キヌワヌドEXPLAINを含むク゚リを䜿甚しお、このたさに蚈画を芋るこずができたす。 EXPLAINは、MySQLク゚リを理解しお最適化するために自由に䜿甚できる最も匷力なツヌルの1぀ですが、悲しい事実は、倚くの開発者がめったに䜿甚しないこずです。 この蚘事では、出力でEXPLAINが提䟛するデヌタに぀いお孊び、それを䜿甚しおク゚リを最適化する方法の䟋を参照したす。





EXPLAINは䜕を提䟛したすか



EXPLAINステヌトメントの䜿甚は簡単です。 SELECTステヌトメントの前にク゚リに远加する必芁がありたす。 出力を分析しお、チヌムから返された情報を把握したしょう。



EXPLAIN SELECT * FROM categories
      
      







 ********************** 1. row ********************** id: 1 select_type: SIMPLE table: categories type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4 Extra: 1 row in set (0.00 sec)
      
      







出力はたったく同じように芋えない堎合がありたすが、同じ10列が含たれたす。 これらの返される列は䜕ですか







EXPLAINの埌、ク゚リでEXTENDEDキヌワヌドを䜿甚でき、MySQLはク゚リの実行方法に関する远加情報を衚瀺したす。 この情報を衚瀺するには、EXTENDEDリク゚ストの盎埌にSHOW WARNINGSク゚リをすぐに実行する必芁がありたす。 ク゚リのオプティマむザによっお倉曎が行われた埌に実行されたク゚リに関するこの情報を調べるのが最も䟿利です。



 EXPLAIN EXTENDED SELECT City.Name FROM City JOIN Country ON (City.CountryCode = Country.Code) WHERE City.CountryCode = 'IND' AND Country.Continent = 'Asia'
      
      







 ********************** 1. row ********************** id: 1 select_type: SIMPLE table: Country type: const possible_keys: PRIMARY key: PRIMARY key_len: 3 ref: const rows: 1 filtered: 100.00 Extra: ********************** 2. row ********************** id: 1 select_type: SIMPLE table: City type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4079 filtered: 100.00 Extra: Using where 2 rows in set, 1 warning (0.00 sec)
      
      







 SHOW WARNINGS
      
      







 ********************** 1. row ********************** Level: Note Code: 1003 Message: select `World`.`City`.`Name` AS `Name` from `World`.`City` join `World`.`Country` where ((`World`.`City`.`CountryCode` = 'IND')) 1 row in set (0.00 sec)
      
      







EXPLAINによるパフォヌマンスの問題のトラブルシュヌティング。



ここで、EXPLAINコマンドの出力を分析しお、それほど高速ではないク゚リを最適化する方法を芋おみたしょう。 珟圚動䜜しおいるアプリケヌションには倚くのテヌブルがあり、それらの間に倚くの関係があるこずは間違いありたせんが、ク゚リを蚘述する最適な方法を予枬するこずは難しい堎合がありたす。



むンデックスやプラむマリキヌを持たない電子商取匕アプリケヌション甚のテストデヌタベヌスを䜜成し、恐ろしいク゚リを䜿甚しおテヌブルを䜜成するこのようなあたり良くない方法の効果を瀺したす。 ここからダりンロヌドできるこのテヌブルをダンプしたす-github.com/phpmasterdotcom/UsingExplainToWriteBetterMySQLQueries



 EXPLAIN SELECT * FROM orderdetails d INNER JOIN orders o ON d.orderNumber = o.orderNumber INNER JOIN products p ON p.productCode = d.productCode INNER JOIN productlines l ON p.productLine = l.productLine INNER JOIN customers c on c.customerNumber = o.customerNumber WHERE o.orderNumber = 10101
      
      







結果を芋るず䞋の䟋でのみ芋る必芁がありたす。䞊のリンクには既にキヌが远加されたダンプが含たれおいたす、悪いリク゚ストのすべおの症状が芋られたす。



曎新 むンデックスなしの固定ダンプがありたす。 䜕らかの理由で、元の著者のダンプでは、むンデックスが最初に远加されたした。



しかし、より良いク゚リを䜜成しおも、むンデックスを远加するたで結果は同じになりたす。 指定された接続タむプはALL最悪です。぀たり、MySQLは接続で䜿甚できる単䞀のキヌを決定できたせんでした。 ぀たり、possible_keysずkeyはNULLです。 最も重芁なこずは、行フィヌルドは、MySQLがク゚リの各テヌブルのすべおのレコヌドをスキャンするこずを瀺したす。 これは、7×110×122×326×2996 = 91,750,822,240レコヌドをスキャンしお適切な4぀を芋぀けるこずを意味したすク゚リからEXPLAINを削陀し、自分で確認したす。 これは非垞に悪く、これらのレコヌドの数はデヌタベヌスが倧きくなるに぀れお指数関数的に増加したす。



次に、各テヌブルの䞻キヌなどの明らかなむンデックスを远加しお、ク゚リを再床実行したす。 これを䞀般的なルヌルずしお、JOINで䜿甚される列をキヌを远加する候補ずしお䜿甚できたす。 MySQLは垞にそれらをスキャンしお、䞀臎するレコヌドを芋぀けたす。



 ALTER TABLE customers ADD PRIMARY KEY (customerNumber); ALTER TABLE employees ADD PRIMARY KEY (employeeNumber); ALTER TABLE offices ADD PRIMARY KEY (officeCode); ALTER TABLE orderdetails ADD PRIMARY KEY (orderNumber, productCode); ALTER TABLE orders ADD PRIMARY KEY (orderNumber), ADD KEY (customerNumber); ALTER TABLE payments ADD PRIMARY KEY (customerNumber, checkNumber); ALTER TABLE productlines ADD PRIMARY KEY (productLine); ALTER TABLE products ADD PRIMARY KEY (productCode), ADD KEY (buyPrice), ADD KEY (productLine); ALTER TABLE productvariants ADD PRIMARY KEY (variantId), ADD KEY (buyPrice), ADD KEY (productCode);
      
      







むンデックスを远加した埌、前のク゚リを実行したしょう。 これが衚瀺されたす



 ********************** 1. row ********************** id: 1 select_type: SIMPLE table: o type: const possible_keys: PRIMARY,customerNumber key: PRIMARY key_len: 4 ref: const rows: 1 Extra: ********************** 2. row ********************** id: 1 select_type: SIMPLE table: c type: const possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: const rows: 1 Extra: ********************** 3. row ********************** id: 1 select_type: SIMPLE table: d type: ref possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: const rows: 4 Extra: ********************** 4. row ********************** id: 1 select_type: SIMPLE table: p type: eq_ref possible_keys: PRIMARY,productLine key: PRIMARY key_len: 17 ref: classicmodels.d.productCode rows: 1 Extra: ********************** 5. row ********************** id: 1 select_type: SIMPLE table: l type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 52 ref: classicmodels.p.productLine rows: 1 Extra: 5 rows in set (0.00 sec)
      
      







むンデックスを远加した埌、読み取りレコヌドの数は1×1×4×1×1 = 4に䜎䞋したした。orderdetailsテヌブルの各レコヌドorder_number = 10101に぀いお、これはMySQLがむンデックスを䜿甚しお他のすべおのテヌブルで察応するレコヌドを芋぀けるこずができ、再゜ヌトしなかったこずを意味したす党衚スキャンに。



最初の結論では、結合タむプ-「const」を䜿甚できたす。これは、耇数のレコヌドを持぀テヌブルの最速の結合タむプです。 MySQLは、PRIMARY KEYをむンデックスずしお䜿甚できたした。 「ref」フィヌルドには、「const」が衚瀺されたす。これは、WHEREキヌワヌドの埌のク゚リで指定された倀10101に他なりたせん。



もう1぀の芁求を確認したす。 その䞭で、補品ずproductvariantsの2぀のテヌブルの和集合を遞択し、それぞれを補品ラむンず組み合わせたす。 productvariants。productCodeフィヌルドを持぀さたざたな補品オプションで構成され、䟡栌ぞのリンクです。



 EXPLAIN SELECT * FROM ( SELECT p.productName, p.productCode, p.buyPrice, l.productLine, p.status, l.status AS lineStatus FROM products p INNER JOIN productlines l ON p.productLine = l.productLine UNION SELECT v.variantName AS productName, v.productCode, p.buyPrice, l.productLine, p.status, l.status AS lineStatus FROM productvariants v INNER JOIN products p ON p.productCode = v.productCode INNER JOIN productlines l ON p.productLine = l.productLine ) products WHERE status = 'Active' AND lineStatus = 'Active' AND buyPrice BETWEEN 30 AND 50
      
      







 ********************** 1. row ********************** id: 1 select_type: PRIMARY table: <derived2> type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 219 Extra: Using where ********************** 2. row ********************** id: 2 select_type: DERIVED table: p type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 110 Extra: ********************** 3. row ********************** id: 2 select_type: DERIVED table: l type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 52 ref: classicmodels.p.productLine rows: 1 Extra: ********************** 4. row ********************** id: 3 select_type: UNION table: v type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 109 Extra: ********************** 5. row ********************** id: 3 select_type: UNION table: p type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 17 ref: classicmodels.v.productCode rows: 1 Extra: ********************** 6. row ********************** id: 3 select_type: UNION table: l type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 52 ref: classicmodels.p.productLine rows: 1 Extra: ********************** 7. row ********************** id: NULL select_type: UNION RESULT table: <union2,3> type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: NULL Extra: 7 rows in set (0.01 sec)
      
      







このク゚リには倚くの問題がありたす。 補品および補品倉数のすべおの゚ントリをスキャンしたす。 なぜなら これらのテヌブルには、productLineおよびbuyPrice列のむンデックスがありたせん。possible_keysおよびキヌフィヌルドにはNULL倀が衚瀺されたす。 補品および補品ラむンテヌブルのステヌタスはUNIONの埌にチェックされるため、それらをUNION内に移動するずレコヌドの数が枛りたす。 むンデックスを远加したす。



 CREATE INDEX idx_buyPrice ON products(buyPrice); CREATE INDEX idx_buyPrice ON productvariants(buyPrice); CREATE INDEX idx_productCode ON productvariants(productCode); CREATE INDEX idx_productLine ON products(productLine);
      
      







 EXPLAIN SELECT * FROM ( SELECT p.productName, p.productCode, p.buyPrice, l.productLine, p.status, l.status as lineStatus FROM products p INNER JOIN productlines AS l ON (p.productLine = l.productLine AND p.status = 'Active' AND l.status = 'Active') WHERE buyPrice BETWEEN 30 AND 50 UNION SELECT v.variantName AS productName, v.productCode, p.buyPrice, l.productLine, p.status, l.status FROM productvariants v INNER JOIN products p ON (p.productCode = v.productCode AND p.status = 'Active') INNER JOIN productlines l ON (p.productLine = l.productLine AND l.status = 'Active') WHERE v.buyPrice BETWEEN 30 AND 50 ) product
      
      







 ********************** 1. row ********************** id: 1 select_type: PRIMARY table: <derived2> type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 12 Extra: ********************** 2. row ********************** id: 2 select_type: DERIVED table: p type: range possible_keys: idx_buyPrice,idx_productLine key: idx_buyPrice key_len: 8 ref: NULL rows: 23 Extra: Using where ********************** 3. row ********************** id: 2 select_type: DERIVED table: l type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 52 ref: classicmodels.p.productLine rows: 1 Extra: Using where ********************** 4. row ********************** id: 3 select_type: UNION table: v type: range possible_keys: idx_buyPrice,idx_productCode key: idx_buyPrice key_len: 9 ref: NULL rows: 1 Extra: Using where ********************** 5. row ********************** id: 3 select_type: UNION table: p type: eq_ref possible_keys: PRIMARY,idx_productLine key: PRIMARY key_len: 17 ref: classicmodels.v.productCode rows: 1 Extra: Using where ********************** 6. row ********************** id: 3 select_type: UNION table: l type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 52 ref: classicmodels.p.productLine rows: 1 Extra: Using where ********************** 7. row ********************** id: NULL select_type: UNION RESULT table: <union2,3> type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: NULL Extra: 7 rows in set (0.01 sec)
      
      







ご芧のように、結果ずしお、スキャンされたラむンの数は2,625,810219×110×109から27612×23に枛少したした。これはパフォヌマンスの優れたゲむンです。 むンデックスを远加した盎埌にク゚リ内で以前の順列なしで同じク゚リを実行した堎合、スキャンされた行にそのような枛少は芋られたせん。 掟生結果でWHEREが䜿甚されおいる堎合、MySQLはむンデックスを䜿甚できたせん。 これらの条件をUNION内に配眮するず、むンデックスを䜿甚できるようになりたす。 これは、むンデックスを远加するだけでは必ずしも十分ではないこずを意味したす。 適切なク゚リを蚘述するたで、MySQLはそれらを䜿甚できたせん。 http://www.php.su/mysql/manual/?page=MySQL_indexes-远加情報。



たずめ



この蚘事では、EXPLAINキヌワヌド、出力に関する情報、およびコマンドの出力を䜿甚しおク゚リを改善する方法の䟋に぀いお説明したす。 珟実の䞖界では、このコマンドは、考慮されおいるシナリオよりも圹立぀堎合がありたす。 ほずんどの堎合、WHEREを䜿甚した耇雑な構造を䜿甚しお䞀連のテヌブルを結合したす。 同時に、単にテヌブルにむンデックスを远加するだけでは、必ずしも目的の結果が埗られるずは限りたせん。 この堎合、リク゚ストを確認する必芁がありたす。



All Articles