我的問題。我認爲我有一個性能查殺子查詢,但無法證明它。我第一次嘗試使用JOIN失敗。 有人可以提供更高性能的解決方案,或確認這確實可以接受,因爲它是?SQL優化:使用任何子查詢查找第一個未查看視頻
我有兩個表,一個包含todo-list(joblist)和一個跟蹤每個用戶進度(userprogress)的表。工作可以,但不能觀看視頻。 (這是一個電子學習網站。)
當觀看視頻時,它們會自動設置爲enum字段上的「已完成」。用戶也可以手動跳過視頻(狀態=「跳過」)。
表結構如下。
要獲取用戶根本沒有看過的第一個視頻(userprogress中沒有記錄)或已開始觀看(status ='started'),我正在使用此查詢。
我已經設置了用於選擇或排序的字段上的索引。但是我不確定他們是否都需要。
SELECT語句有兩個部分
- 的內部子查詢,我在那裏取都見過或跳過視頻
- 主要發言,我在那裏取第一視頻不中(1)
有一個用於PHP(:email)的命名參數,以避免SQL注入。
SELECT jl.where_to_do_it FROM joblist AS jl
INNER JOIN userprogress AS up
ON (jl.joblistID = up.joblistID)
WHERE jl.what_to_do = 'video'
AND jl.joblistID NOT IN
(
SELECT injl.joblistID
FROM joblist AS injl
INNER JOIN userprogress AS inup
ON (injl.joblistID = inup.joblistID)
WHERE
(inup.status = 'finished' OR inup.status = 'skipped')
AND
inup.email = :email
AND
injl.what_to_do = 'video'
)
ORDER BY jl.joborder ASC
LIMIT 0,1
這是EXPLAIN輸出,這我需要一些幫助理解。
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY jl ref PRIMARY,what_to_do what_to_do 602 const 9 Using where; Using filesort
1 PRIMARY up ref joblistID joblistID 3 jl.joblistID 1 Using index
2 DEP-SUB injl eq_ref PRIMARY,what_to_do PRIMARY 3 func 1 Using where
2 DEP-SUB inup eq_ref nodup,email,joblistID,status nodup 455 const,func 1 Using where
在CREATE TABLE命令:
CREATE TABLE IF NOT EXISTS `joblist` (
`joblistID` mediumint(10) unsigned NOT NULL AUTO_INCREMENT,
`what_to_do` varchar(200) COLLATE utf8_swedish_ci NOT NULL,
`where_to_do_it` varchar(100) COLLATE utf8_swedish_ci NOT NULL,
`joborder` mediumint(6) NOT NULL,
`track` enum('fast','slow','bonus') COLLATE utf8_swedish_ci NOT NULL DEFAULT 'slow',
`chapter` tinyint(11) unsigned NOT NULL COMMENT 'What book chapter it relates to',
PRIMARY KEY (`joblistID`),
KEY `nodupjobs` (`joborder`,`chapter`),
KEY `what_to_do` (`what_to_do`),
KEY `where_to_do_it` (`where_to_do_it`),
KEY `joborder` (`joborder`),
KEY `track` (`track`),
KEY `chapter` (`chapter`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci COMMENT='Suggested working order';
CREATE TABLE IF NOT EXISTS `userprogress` (
`upID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(150) COLLATE utf8_swedish_ci NOT NULL COMMENT 'user id',
`joblistID` mediumint(9) unsigned NOT NULL COMMENT 'foreign key',
`progressdata` varchar(300) COLLATE utf8_swedish_ci DEFAULT NULL COMMENT 'JSON object describing progress',
`percentage_complete` tinyint(3) unsigned DEFAULT NULL,
`status` enum('begun','skipped','finished') COLLATE utf8_swedish_ci DEFAULT 'begun',
`lastupdate` datetime NOT NULL,
`approved` datetime DEFAULT NULL,
PRIMARY KEY (`upID`),
UNIQUE KEY `nodup` (`email`,`joblistID`),
KEY `email` (`email`),
KEY `joblistID` (`joblistID`),
KEY `status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci COMMENT='Keep track of what the user has done';
我有兩個工作(和一個不工作)的答案。到目前爲止,我只有兩個人都贊成。如果一個人相對於另一個人有明顯的優勢,那麼在決定接受哪一個作爲接受的答案時,我需要幫助。 (或者也許有人會提出一個更好的解決方案。)我會等待一兩天,然後才能將答案設置爲已接受。 – itpastorn 2012-08-17 11:28:28