2017-08-24 82 views
0

我沒有關於如何優化此查詢的其他想法,運行大約2,5秒的goodsXML表超過200萬行。它看起來像順序減慢了很多,但我不能刪除它。此外,這取決於在這裏選擇多少項目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'。如果每個gx.id(通過'shopAddress'?)獲得多於1行,則使用'shopAddress'的'if'-term將使用隨機行,因此您可能會得到錯誤的結果。如果你每gx.id獲得1行,你不需要'group by'。 2.'by by'確實會減慢查詢速度,因爲它不能使用索引。嘗試預先計算:'imExist'可以通過觸發器設置(您可能已經這麼做了,但是列被您的查詢隱藏,重新定義了'imExist')。也許'isActual'也是可能的(最糟糕的情況是:通過小時腳本,idealy:找到一個值,自然會給你這個順序)。 – Solarflare

回答

1

EXPLAIN表明,它需要掃描約82K的行gx。顯然,categoryID = 892有很多行,對嗎?其餘的大部分都很簡單JOINs

  • 請勿使用MyISAM,請使用InnoDB。
  • INT(6) - (6)沒有任何意義。也許你的意思是MEDIUMINT UNSIGNEDINT是4個字節; MEDIUMINT是3.
  • 您是否在'始終在尋找category?如果是這樣,通過切換到PRIMARY KEY (categoryID, id), INDEX(id)來利用InnoDB的「集羣」PK,並從categoryID開始查找兩個現有索引。
  • 請勿使用CHAR,除非該列是真正固定的長度;使用VARCHAR
  • 請勿使用FLOAT(m,n),否則會導致細微的舍入誤差。對於金錢,使用DECIMAL(m,n);科學價值觀,請使用FLOAT
  • ORs失敗優化。看看你是否可以重新設計架構以避免其中的一些。
  • 什麼是LIKE '%^598^%'?你有這個專欄中的數字列表嗎?
  • 切換到InnoDB後,將key_buffer_size減少到只有30M,並將innodb_buffer_pool_size增加到可用RAM的70%。