2017-08-24 7 views
0

このクエリを最適化する方法については他にはありませんが、2万個以上の行のgoodsXMLテーブルで約2,5秒実行します。それは注文のように見えるが、多くの速度が低下しているようだが、私はそれを削除することはできません。また、ここで選択したアイテム数には多くの違いがあります。gx.categoryID IN(892)、後で別のテーブルがこのアイテムセットを結合するためです。私は結合されたテーブルがwhere句で実行するので、このオプションの後に結合を行うことはできません。MySQLのクエリは大きなテーブルでは遅い

SELECT MD5(CONCAT(gx.id,598)) citySort,gx.dateCreated lastModifiedSince,IF(DATE(gx.dateModified)>=(IF((EXTRACT(HOUR FROM NOW()) BETWEEN 0 AND 6),DATE(NOW() -INTERVAL 6 HOUR),DATE(NOW()))) OR DATE(gx.dateModified)>=DATE(NOW()),1,0) isActual, 
     gx.id,p.producerName,gx.categoryID,gx.name,CONCAT('::',gxi.imageName) images,IF(CONCAT('::',gxi.imageName)!='',1,0) imExist,gx.price,gx.oldPrice,gx.oldPricePt,gx.sourceUrl,IF(s.offerPostingType='XML',IF(s.alternateName!='',s.alternateName,s.name),CONCAT(u.lastName,' ',u.name)) shopName,s.logoName, 
     s.id shopID,s.active shopActive,s.offerPostingType,c.titleAdd,'Москва' cityName, 
     IF((s.cityID='598' AND s.deliveryByCity=1) OR (sa.cityID='598' AND sa.deliveryByCity=1) OR (s.deliveryByMRCities LIKE '%^598^%' AND s.deliveryByMR=1),1,0) deliveryInYourCity, 
     IF(s.deliveryByCityAll=1 OR (s.cityID='598' AND s.deliveryByCity=1) OR (sa.cityID='598' AND sa.deliveryByCity=1) OR (s.deliveryByMRCities LIKE '%^598^%' AND s.deliveryByMR=1),1,0) deliveryByCity, 
     IF(s.deliveryByMail=1,1,0) deliveryByMail, 
     IF(s.deliveryBySelfAll=1 OR (s.cityID='598' AND s.deliveryBySelf=1) OR (sa.cityID='598' AND sa.deliveryBySelf=1),1,0) deliveryBySelf 
     FROM goodsXML gx 
     JOIN category c ON c.id=gx.categoryID 
     LEFT JOIN producer p ON p.id=gx.producerID 
     JOIN shop s ON s.id=gx.shopID 
     LEFT JOIN shopAddress sa ON sa.shopID=s.id 
     LEFT JOIN users u ON u.id=s.userID 
     LEFT JOIN goodsXMLImages gxi ON gxi.goodsXMLID=gx.id AND gxi.isMain = 1 

     WHERE 1=1 AND (s.cityID='598' OR s.deliveryByCityAll=1 OR s.deliveryBySelfAll=1 OR s.deliveryByMail=1 OR sa.cityID='598' OR (s.deliveryByMR=1 AND s.deliveryByMRCities LIKE '%^598^%')) AND (s.isPaying=0 OR u.balance>0) AND gx.categoryID IN(892) 
     GROUP BY gx.id 

     ORDER BY isActual DESC,imExist DESC,gx.PPC DESC,gx.payPrior ASC,citySort DESC 
     LIMIT 0,40 

説明は以下の通りです:

+----+-------------+-------+--------+--------------------------------+-----------------+----------------+------------------------+--------------------+--------------------------------+ 
| ID | SELECT_TYPE | TABLE | TYPE |   POSSIBLE_KEYS   |  KEY  | KEY_LEN  |   REF   |  ROWS  |    EXTRA    | 
+----+-------------+-------+--------+--------------------------------+-----------------+----------------+------------------------+--------------------+--------------------------------+ 
| |    |  |  |        |     |    |      |     |        | 
| 1 | SIMPLE  | c  | const | PRIMARY      | PRIMARY   | 4    | const     | 1     | Using temporary; Using filesor | 
| |    |  |  |        |     |    |      |     |        | 
| 1 | SIMPLE  | gx | ref | ixGroupNameCategoryIDShopIDPro | ixCategoryID... | ixCategoryIDid | 4      | const    | 82005       | 
| |    |  |  | ducerID      |     |    |      |     |        | 
| |    |  |  |        |     |    |      |     |        | 
| 1 | SIMPLE  | s  | eq_ref | PRIMARY      | deliveryByMR | PRIMARY  | 4      | vsesrazu.gx.shopID | 1        | 
| |    |  |  |        |     |    |      |     |        | 
| 1 | SIMPLE  | sa | ref | shopKey      | shopKey   | 5    | vsesrazu.s.id   | 2     | Using where     | 
| |    |  |  |        |     |    |      |     |        | 
| 1 | SIMPLE  | u  | eq_ref | PRIMARY      | PRIMARY   | 4    | vsesrazu.s.userID  | 1     | Using where     | 
| |    |  |  |        |     |    |      |     |        | 
| 1 | SIMPLE  | p  | eq_ref | PRIMARY      | PRIMARY   | 4    | vsesrazu.gx.producerID | 1     |        | 
| |    |  |  |        |     |    |      |     |        | 
| 1 | SIMPLE  | gxi | ref | over       | over   | 4    | vsesrazu.gx.id   | 1     |        | 
+----+-------------+-------+--------+--------------------------------+-----------------+----------------+------------------------+--------------------+--------------------------------+ 

ショーgoodsXML用のテーブルを作成します。

CREATE TABLE goodsXML (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
localID char(255) NOT NULL, 
groupID char(255) DEFAULT NULL, 
dateCreated datetime NOT NULL, 
dateModified datetime NOT NULL, 
dateModifiedPrice datetime NOT NULL, 
name char(255) DEFAULT NULL, 
nameHash char(32) NOT NULL, 
groupName char(255) DEFAULT NULL, 
newGroupName char(255) NOT NULL, 
url char(255) NOT NULL, 
sourceUrl char(255) NOT NULL, 
categoryID int(6) unsigned NOT NULL, 
producerID int(6) DEFAULT NULL, 
authorID int(6) DEFAULT NULL, 
shopID int(6) NOT NULL, 
XMLUrlOrder tinyint(2) NOT NULL, 
price float(12,2) NOT NULL, 
oldPrice float(12,2) NOT NULL, 
oldPricePt smallint(3) NOT NULL, 
description text, 
descriptionHash char(32) NOT NULL, 
descriptionForGroup text NOT NULL, 
imExist tinyint(1) NOT NULL DEFAULT '0', 
imagesForGroup tinyint(1) NOT NULL DEFAULT '0', 
videoHighlight text NOT NULL, 
videoSiteUrl char(255) NOT NULL, 
videoChannelUrl char(255) NOT NULL, 
plusesMinuses text NOT NULL, 
toIndex tinyint(1) NOT NULL DEFAULT '0', 
isRST tinyint(1) NOT NULL DEFAULT '0', 
isReplica tinyint(1) NOT NULL DEFAULT '0', 
status tinyint(1) NOT NULL DEFAULT '0', 
comment char(255) NOT NULL, 
daysLeft tinyint(2) NOT NULL, 
PPC float(5,2) DEFAULT '0.00', 
payPrior tinyint(1) NOT NULL DEFAULT '4', 
PRIMARY KEY (id), 
UNIQUE KEY ixGroupNameCategoryIDShopIDProducerID (shopID,localID), 
KEY ixGroupNameCategoryID (groupName,categoryID), 
KEY ixStatusShopID (status,shopID), 
KEY ixCategoryID (categoryID), 
KEY authorID (authorID), 
KEY ixDateModified (dateModified,imExist), 
KEY daysLeft (daysLeft), 
KEY sourceUrl (sourceUrl), 
KEY ixCategoryIDid (categoryID,id) 
) ENGINE=MyISAM AUTO_INCREMENT=4218880 DEFAULT CHARSET=utf8 
+0

1. 'group by'を削除します。 1つのgx.id( 'shopAddress'によって?)を1行以上取得すると、' shopAddress'を使う 'if'-termはランダムな行を使います。 gx.idごとに1行が得られれば、 'group by'は必要ありません。 2. 'order by'はインデックスを使用できないため、クエリの実行速度を遅くします。あらかじめ計算してみてください: 'imExist'はトリガーによって設定できます(あなたはすでにそれを実行しているかもしれませんが、' imExist'を再定義するクエリによってカラムが隠されます)。たぶんisActualでも可能です(最悪の場合:1時間ごとのスクリプト、理想:自然にその順序を与える値を見つけること)。 – Solarflare

答えて

1

EXPLAINは、それがgx約82K行をスキャンする必要があることを示しています。明らかに多くの行がcategoryID = 892で正しいと思われますか?残りのほとんどは簡単ですJOINs

  • MyISAMを使用しないでください。InnoDBを使用してください。
  • INT(6) - (6)は何も意味しません。おそらくMEDIUMINT UNSIGNEDを意味するのでしょうか? INTは4バイトです。 MEDIUMINTは3です。
  • 「常に」categoryで検索していますか?その場合は、PRIMARY KEY (categoryID, id), INDEX(id)に切り替えてcategoryIDで始まる2つの既存インデックスをチャッキングして、InnoDBの「クラスタ化」PKを使用してください。
  • CHARは、列が本当に固定長でない限り使用しないでください。 VARCHARを使用してください。
  • FLOAT(m,n)を使用しないと、微妙な丸め誤差が発生する可能性があります。 Moneyの場合はDECIMAL(m,n)を使用します。科学値の場合はFLOATを使用します。
  • ORs敗北最適化。それらのいくつかを避けるためにスキーマを再設計できるかどうかを確認してください。
  • LIKE '%^598^%'とは何ですか?その列に数字のリストがありますか?
  • InnoDBに切り替えた後、key_buffer_sizeを30Mに減らし、innodb_buffer_pool_sizeを使用可能なRAMの70%に増やしてください。
関連する問題