2014-09-27 50 views
1

以下查詢花費時間(2.3s)執行。如何提高查詢執行的性能

SELECT *, COUNT(c2.id) AS c2__0 
FROM countryMaster c, stateMaster s, cityMaster c2, categoryMaster c3, categoryMaster c4, product p 
INNER JOIN user u ON ((u.id = p.user_id AND u.is_active = 1)) 
WHERE (p.category_id = c4.id 
AND c2.id = p.x_area_id 
AND c2.parent_id = s.id 
AND s.parent_id = c.id AND c3.id IN ('1271') 
AND c4.rgt = (c4.lft + 1) 
AND c4.lft BETWEEN c3.lft AND c3.rgt AND p.status = 1) 
GROUP BY c.id; 


Explain:  
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: c3 
     type: const 
possible_keys: PRIMARY,lft_rgt_inx 
      key: PRIMARY 
     key_len: 4 
      ref: const 
     rows: 1 
     Extra: Using temporary; Using filesort 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: p 
     type: ALL 
possible_keys: INX_cmp_sx,status 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 29958 
     Extra: Using where 
*************************** 3. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: c4 
     type: eq_ref 
possible_keys: PRIMARY,lft_rgt_inx 
      key: PRIMARY 
     key_len: 4 
      ref: yozoa1_live.p.category_id 
     rows: 1 
     Extra: Using where 
*************************** 4. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: u 
     type: eq_ref 
possible_keys: PRIMARY,is_active 
      key: PRIMARY 
     key_len: 4 
      ref: yozoa1_live.p.user_id 
     rows: 1 
     Extra: Using where 
*************************** 5. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: c2 
     type: eq_ref 
possible_keys: PRIMARY,parent_id 
      key: PRIMARY 
     key_len: 4 
      ref: yozoa1_live.p.x_area_id 
     rows: 1 
     Extra: 
*************************** 6. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: s 
     type: eq_ref 
possible_keys: PRIMARY,parent_id 
      key: PRIMARY 
     key_len: 4 
      ref: yozoa1_live.c2.parent_id 
     rows: 1 
     Extra: 
*************************** 7. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: c 
     type: eq_ref 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: yozoa1_live.s.parent_id 
     rows: 1 
     Extra: 


Show create table -  
CREATE TABLE `categoryMaster` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) NOT NULL, 
    `description` text NOT NULL, 
    `logo` varchar(255) NOT NULL, 
    `is_visible` tinyint(1) NOT NULL DEFAULT '1', 
    `is_featured` tinyint(1) NOT NULL DEFAULT '0', 
    `is_map` tinyint(1) NOT NULL DEFAULT '0', 
    `is_price_required` tinyint(1) NOT NULL DEFAULT '1', 
    `parent_id` int(11) NOT NULL DEFAULT '0', 
    `lft` int(11) NOT NULL DEFAULT '0', 
    `rgt` int(11) NOT NULL DEFAULT '0', 
    `level` tinyint(4) NOT NULL DEFAULT '0', 
    `sort_order` smallint(6) NOT NULL DEFAULT '0', 
    `product_count` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `lft_rgt_inx` (`lft`,`rgt`), 
    KEY `parent_id` (`parent_id`), 
    KEY `product_count` (`product_count`) 
) ENGINE=MyISAM 


CREATE TABLE `productMaster` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) NOT NULL, 
    `description` longtext NOT NULL, 
    `sub_name` varchar(255) NOT NULL, 
    `sub_description` longtext NOT NULL, 
    `image` varchar(255) NOT NULL, 
    `category_id` int(11) NOT NULL, 
    `is_new` tinyint(1) NOT NULL DEFAULT '1', 
    `status` tinyint(1) NOT NULL DEFAULT '-1', 
    `user_id` int(11) NOT NULL, 
    `currency_main` varchar(4) NOT NULL DEFAULT 'MNT', 
    `price_original` double NOT NULL DEFAULT '0', 
    `price_global` double NOT NULL DEFAULT '0', 
    `attribute_value_ids` text, 
    `created_at` datetime DEFAULT NULL, 
    `updated_at` datetime DEFAULT NULL, 
    `confirmed_at` datetime DEFAULT NULL, 
    `duration` int(4) NOT NULL DEFAULT '7', 
    `rental_duration` varchar(50) DEFAULT NULL, 
    `buy_online` tinyint(1) NOT NULL DEFAULT '0', 
    `internal` tinyint(1) NOT NULL DEFAULT '0', 
    `delivery_status` smallint(1) NOT NULL DEFAULT '1' 
    `delivery_type` smallint(1) NOT NULL DEFAULT '1' 
    `phone_cell` varchar(50) DEFAULT NULL, 
    `phone_home` varchar(50) DEFAULT NULL, 
    `surname` varchar(100) DEFAULT NULL, 
    `x_area_id` int(11) NOT NULL, 
    `x_area_location_id` int(11) DEFAULT NULL, 
    `sublocality_id` int(11) DEFAULT NULL, 
    `product_posting_price` double NOT NULL, 
    `is_paid` tinyint(1) NOT NULL, 
    `product_posting_currency` varchar(3) NOT NULL, 
    `map_lat` double NOT NULL, 
    `map_lng` double NOT NULL, 
    `product_company_contact_info_id` int(11) NOT NULL, 
    `backup_status` tinyint(1) NOT NULL DEFAULT '4', 
    `is_scraped` tinyint(1) DEFAULT NULL, 
    `sources_id` int(3) NOT NULL, 
    `product_source_url` varchar(255) NOT NULL, 
    `country_id` int(4) NOT NULL, 
    `state_id` int(5) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `UNQ_cmp_icsu` (`id`,`category_id`,`status`,`user_id`), 
    KEY `country_id` (`country_id`), 
    KEY `state_id` (`state_id`), 
    KEY `INX_cmp_sx` (`status`,`x_area_id`), 
    KEY `status` (`status`), 
    FULLTEXT KEY `name` (`name`), 
    FULLTEXT KEY `attribute_value_ids` (`attribute_value_ids`) 
) ENGINE=MyISAM 


CREATE TABLE `cityMaster` (
    `id` int(10) NOT NULL AUTO_INCREMENT, 
    `parent_id` int(6) NOT NULL, 
    `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, 
    `map_lat` double NOT NULL, 
    `map_lng` double NOT NULL, 
    `has_sublocality` tinyint(1) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`id`), 
    KEY `parent_id` (`parent_id`) 
) ENGINE=MyISAM 


CREATE TABLE `stateMaster` (
    `id` int(6) NOT NULL AUTO_INCREMENT, 
    `parent_id` int(3) NOT NULL, 
    `name` varchar(255) NOT NULL, 
    `map_lat` double NOT NULL, 
    `map_lng` double NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `parent_id` (`parent_id`) 
) ENGINE=MyISAM 


CREATE TABLE `countryMaster` (
    `id` int(3) NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) NOT NULL, 
    `country_code` varchar(2) CHARACTER SET latin1 NOT NULL, 
    `map_lat` double NOT NULL, 
    `map_lng` double NOT NULL, 
    `is_active` tinyint(1) NOT NULL DEFAULT '1', 
    PRIMARY KEY (`id`) 
) ENGINE=MyISAM 

請指教我如何減少帶索引的查詢的執行時間。 也讓我知道爲什麼查詢解釋在ref列中顯示null? 也讓我知道優化查詢的步驟?

+0

用戶表丟失? – hkulekci 2014-10-14 22:16:48

+0

嘗試在productMaster中的x_area_id上添加索引。 – evanv 2014-11-08 16:15:17

回答

2

好吧,看看這個,我想你需要做的是在x_area_id上添加一個索引到productMaster,或者可能是一個多列索引。這裏的原因:

SELECT *, COUNT(c2.id) AS c2__0 
FROM countryMaster c, stateMaster s, cityMaster c2, categoryMaster c3, categoryMaster c4, product p 
INNER JOIN user u ON ((u.id = p.user_id AND u.is_active = 1)) 
WHERE (p.category_id = c4.id 
AND c2.id = p.x_area_id 
AND c2.parent_id = s.id 
AND s.parent_id = c.id AND c3.id IN ('1271') 
AND c4.rgt = (c4.lft + 1) 
AND c4.lft BETWEEN c3.lft AND c3.rgt AND p.status = 1) 
GROUP BY c.id; 

注意連接條件在這裏:

AND c2.id = p.x_area_id 

而且還注意到,在產品主表,你有

PRIMARY KEY (`id`), 
    UNIQUE KEY `UNQ_cmp_icsu` (`id`,`category_id`,`status`,`user_id`), 
    KEY `country_id` (`country_id`), 
    KEY `state_id` (`state_id`), 
    KEY `INX_cmp_sx` (`status`,`x_area_id`), 
    KEY `status` (`status`), 
    FULLTEXT KEY `name` (`name`), 
    FULLTEXT KEY `attribute_value_ids` (`attribute_value_ids`) 

指數值得注意的是,不x_area_id。

SQL正在提可能的密鑰的事實與您的SQL語句的這部分做的事:

AND c4.lft BETWEEN c3.lft AND c3.rgt AND p.status = 1) 

從本質上說,SQL已經注意到,它可能是能夠使用的事實,狀態= 1利用INX_cmp_sx鍵。我在MyISAM中做了很多工作已經有一段時間了,但我懷疑這是因爲它選擇使用p.user_id上的索引來針對用戶表進行連接,並且查詢優化器決定不執行索引合併。

如果是我,我會嘗試兩件事。首先,我試着簡單地在x_area_id上添加一個關鍵字,然後看看它是否會提高性能(顯然,明確地運行解釋)。如果沒有,那麼我會考慮在(user_id,status和x_area_id)上添加一個複合索引。究竟哪一列應該是索引中的第一個,從這個角度來看我完全清楚......我猜想狀態,但是你需要測試它。

另外,我想指出的是,狀態指數,你對productMaster表

KEY `INX_cmp_sx` (`status`,`x_area_id`), 
    KEY `status` (`status`), 

是多餘的,因爲INX_cmp_sx關鍵的。所以你可能想嘗試用(user_id,status和x_area_id)或(user_id,x_area_id,status)之類的東西替換狀態索引或者沿着這些行。

技術上你可以只索引這些都分開,但有時也有一種傾向,回火(如http://www.percona.com/blog/2009/09/19/multi-column-indexes-vs-index-merge/

底線:擺脫狀態鍵,並用的(USER_ID,狀態有些變化替換它,和x_area_id)。即使嘗試擺脫INX_cmp_sx並將其替換爲(status,user_id,x_area_id)或(status,x_area_id,user_id)。你的解釋的輸出基本上告訴你,MySQL無法找到一種方法來拉出與((status,user_id,x_area_id)組合相對應的數據的橫截面,這將更加高效,只需讀取整個productMaster表。玩弄這些列的索引,你會發現一些效果更好的東西。而且,再次,簡單地添加x_area_id將有可能將這一切全部弄清楚。我肯定會先給一個鏡頭。