2013-03-20 136 views
-1

查詢花費的時間太長。此查詢來自網絡應用程序。 它影響了我們的表現。任何人請幫助我重寫它,並與我分享您的寶貴建議。查詢花費的時間太長,影響我們的性能

查詢有了解釋計劃:

mysql> explain SELECT DISTINCT(tab2.idnum) FROM (`tab2`) JOIN `tab1` ON tab1.question = tab2.idnum WHERE `department` = 'Biology' AND tab2.status != 'active' AND tab2.status != 'retired' AND (tab2.instructor = 164604 OR tab2.instructor = 194703) AND tab1.topic IN (SELECT `topic` FROM (`tab5`) JOIN `tab4` ON tab4.chapter = tab5.id WHERE `book` = 1000) AND tab2.idnum NOT IN (SELECT `question` FROM (`tab3`) WHERE `book` = 1000 AND `isPR` = 1) AND `questiontype` IN ('mult') limit 2; 
+----+--------------------+-----------------+-----------------+------------------+---------+---------+-------------------------------+--------+-------------------------------------------+ 
| id | select_type  | table   | type   | possible_keys | key  | key_len | ref       | rows | Extra          | 
+----+--------------------+-----------------+-----------------+------------------+---------+---------+-------------------------------+--------+-------------------------------------------+ 
| 1 | PRIMARY   | tab1 | index   | question   | tq  | 8  | NULL       | 149899 | Using where; Using index; Using temporary | 
| 1 | PRIMARY   | tab2 | eq_ref   | PRIMARY   | PRIMARY | 4  | comp1.tab1.question |  1 | Using where        | 
| 3 | DEPENDENT SUBQUERY | tab3 | unique_subquery | qb,question,book | qb  | 8  | func,const     |  1 | Using where        | 
| 2 | DEPENDENT SUBQUERY | tab4 | ref    | chapter,topic | topic | 4  | func       |  1 |           | 
| 2 | DEPENDENT SUBQUERY | tab5  | eq_ref   | PRIMARY   | PRIMARY | 4  | comp1.tab4.chapter |  1 | Using where        | 
+----+--------------------+-----------------+-----------------+------------------+---------+---------+-------------------------------+--------+-------------------------------------------+ 
5 rows in set (0.00 sec) 

表結構:

mysql> show create table tab5\G 
*************************** 1. row *************************** 
     Table: tab5 
Create Table: CREATE TABLE `tab5` (
    `name` varchar(255) CHARACTER SET utf8 DEFAULT NULL, 
    `descrip` mediumtext NOT NULL, 
    `category` varchar(255) NOT NULL DEFAULT '', 
    `order` int(11) NOT NULL DEFAULT '0', 
    `department` varchar(255) NOT NULL DEFAULT '', 
    `book` int(11) NOT NULL DEFAULT '0', 
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `is_trial` tinyint(1) NOT NULL DEFAULT '0', 
    `is_live` tinyint(1) NOT NULL DEFAULT '1', 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=6305 DEFAULT CHARSET=latin1 

mysql> show create table tab4\G 
*************************** 1. row *************************** 
     Table: tab4 
Create Table: CREATE TABLE `tab4` (
    `chapter` int(11) NOT NULL DEFAULT '0', 
    `topic` int(11) NOT NULL DEFAULT '0', 
    KEY `chapter` (`chapter`), 
    KEY `topic` (`topic`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
1 row in set (0.00 sec) 

mysql> show create table tab3\G 
*************************** 1. row *************************** 
     Table: tab3 
Create Table: CREATE TABLE `tab3` (
    `question` int(11) NOT NULL, 
    `book` int(11) NOT NULL, 
    `isPR` tinyint(1) unsigned NOT NULL DEFAULT '0', 
    UNIQUE KEY `qb` (`question`,`book`), 
    KEY `question` (`question`), 
    KEY `book` (`book`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
1 row in set (0.00 sec) 

mysql> show create table tab2 \G 
*************************** 1. row *************************** 
     Table: tab2 
Create Table: CREATE TABLE `tab2` (
    `idnum` int(11) NOT NULL AUTO_INCREMENT, 
    `questiontype` enum('mult','CM','GO','FIB','AUD','HS','DD') NOT NULL DEFAULT 'def1', 
    `question` mediumtext NOT NULL, 
    `difficulty` int(3) DEFAULT '0', 
    `createdby` int(11) NOT NULL DEFAULT '0', 
    `createdwhen` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `status` enum('active','calibrating','onhold','retired') NOT NULL DEFAULT 'def1', 
    `parent` int(11) NOT NULL DEFAULT '0', 
    `child` int(11) NOT NULL DEFAULT '0', 
    `family` int(11) NOT NULL DEFAULT '0', 
    `department` varchar(255) NOT NULL DEFAULT '', 
    `notes` text NOT NULL, 
    `instructor` int(11) NOT NULL DEFAULT '0', 
    `nmfilter` enum('everyone','majors only','undetermined') NOT NULL DEFAULT 'def1', 
    `PR` int(11) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`idnum`), 
    KEY `family` (`family`) 
) ENGINE=InnoDB AUTO_INCREMENT=186724 DEFAULT CHARSET=latin1 
1 row in set (0.00 sec) 

mysql> show create table tab1\G 
*************************** 1. row *************************** 
     Table: tab1 
Create Table: CREATE TABLE `tab1` (
    `question` int(11) NOT NULL DEFAULT '0', 
    `topic` int(11) NOT NULL DEFAULT '0', 
    KEY `question` (`question`), 
    KEY `topic` (`topic`), 
    KEY `tq` (`topic`,`question`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
1 row in set (0.00 sec) 
+0

避免'DISTINCT'。如果只有一個值可能,你爲什麼使用'IN'?嘗試通過連接替換子選擇。你在過濾的列上有索引嗎? – Kai 2013-03-20 10:07:54

+0

請寄給我那個查詢。 – pvr 2013-03-20 11:08:07

+0

根據您最近的問題,請儘量避免讓人們爲您重寫您的查詢 - 請求幫助,然後應用您收到的建議要好得多。 – halfer 2013-04-22 12:25:00

回答

2

這是一個複雜的分析。嘗試創建SQL小提琴來更好地理解你的問題。 而我的建議是,儘量只用JOIN來重寫查詢(刪除嵌套查詢),並嘗試下面的查詢,

SELECT tab2.idnum 
FROM (`tab2`) INNER JOIN `tab1` ON tab1.question = tab2.idnum INNER JOIN `tab3` ON tab2.idnum != tab3.question INNER JOIN `tab5` ON tab1.topic = tab5.topics 
INNER JOIN `tab4` ON tab4.chapter = tab5.id 
WHERE 
tab5.department = 'Biology' AND tab2.status != 'active' AND tab2.status != 'retired' AND 
(tab2.instructor = 164604 OR tab2.instructor = 194703) 
AND tab5.book = 1000 AND tab3.book = 1000 AND tab3.isPR = 1 
AND tab2.questiontype IN ('mult') 

注:因爲我不知道你想達到什麼樣的,我刪除了一些像DISTINCT,LIMIT這樣的東西。但我希望這會給你想法如何處理這個問題。

爲了給出更多相關答案,只需使用表格和數據上傳文章或創建sqlfiddle並從這些表格中解釋您想實現的目標以及您與他們之間的關係。

編輯:

SELECT tab2.idnum 
FROM (`tab2`) INNER JOIN `tab1` ON tab1.question = tab2.idnum AND (tab2.status != 'active' AND tab2.status != 'retired' AND (tab2.instructor = 164604 OR tab2.instructor = 194703) AND tab2.questiontype IN ('mult')) 
INNER JOIN `tab3` ON tab2.idnum != tab3.question AND tab3.book = 1000 AND tab3.isPR = 1 
INNER JOIN `tab5` ON tab1.topic = tab5.topics AND tab5.department = 'Biology' AND tab5.book = 1000 
INNER JOIN `tab4` ON tab4.chapter = tab5.id 

注意:要提高速度,確保你的索引,有多少行存在於表,並限制查詢的結果。

EDIT2:

SELECT tab2.idnum 
FROM `tab2` INNER JOIN `tab1` ON tab1.question = tab2.idnum AND (tab2.status != 'active' AND tab2.status != 'retired' AND (tab2.instructor = 164604 OR tab2.instructor = 194703) AND tab2.questiontype IN ('mult')) 
INNER JOIN `tab3` ON tab2.idnum != tab3.question AND tab3.book = 1000 AND tab3.isPR = 1 
INNER JOIN `tab5` ON tab5.department = 'Biology' AND tab5.book = 1000 
INNER JOIN `tab4` ON tab4.chapter = tab5.id 
WHERE tab1.topic = tab4.topic 
+0

@pvr,我編輯了我的文章,並確保在「註釋」中提到的東西。如果問題仍然存在,請在http://sqlfiddle.com中提供您的表格。 – 2013-03-21 07:01:56

+0

請在這裏找到sql小提琴鏈接。上面的查詢是拋出錯誤。 http://www.sqlfiddle.com/#!2/b1b57/4 – pvr 2013-03-22 08:44:13

+0

請使用一些虛擬數據更新sqlfiddle。嘗試在EDIT2中提供的查詢的一部分 – 2013-03-22 09:13:19