2011-10-20 62 views
0

在同一個數據庫我有一個表messages whos列:id,title,text我想要的。我只想要其中title在表lastlogon中沒有條目的記錄,其名稱相當於。從一個表格中去除另一個表格的值。超慢

我一直在使用PHP中的SQL命令,它通常花2-3秒拉起來:

SELECT DISTINCT * FROM messages WHERE title NOT IN (SELECT username FROM lastlogon) LIMIT 1000

這些都是好,直到表lastlogon開始產生的約80%值表格messages。消息有大約8000個條目,lastlogon大約有7000條。現在大約需要1分鐘到2分鐘才能完成。 MySQL會導致非常高的CPU使用率。

我嘗試以下,但沒有運氣減少時間:

SELECT id,title,text FROM messages a LEFT OUTER JOIN lastlogon b ON (a.title = b.username) LIMIT 1000

爲什麼突然需要這麼長的時間條目的如此低的量?我試過多次重啓mysql和apache。我正在使用debian linux。

編輯:這裏有結構

-- 
-- Table structure for table `lastlogon` 
-- 

CREATE TABLE IF NOT EXISTS `lastlogon` (
    `username` varchar(25) NOT NULL, 
    `lastlogon` date NOT NULL, 
    `datechecked` date NOT NULL, 
    PRIMARY KEY (`username`), 
    KEY `username` (`username`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

-- -------------------------------------------------------- 

-- 
-- Table structure for table `messages` 
-- 

CREATE TABLE IF NOT EXISTS `messages` (
    `id` smallint(9) unsigned NOT NULL AUTO_INCREMENT, 
    `title` varchar(255) NOT NULL, 
    `name` varchar(255) NOT NULL, 
    `email` varchar(50) NOT NULL, 
    `text` mediumtext, 
    `folder` tinyint(2) NOT NULL, 
    `read` smallint(5) unsigned NOT NULL, 
    `dateline` int(10) unsigned NOT NULL, 
    `ip` varchar(15) NOT NULL, 
    `attachment` varchar(255) NOT NULL, 
    `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    `username` varchar(300) NOT NULL, 
    `error` varchar(500) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `title` (`title`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=9010 ; 

編輯2

編輯結構,新的索引。 把一個指標上都messages.title和lastlogon.username後,我想出了以下結果:

顯示行0 - 29(623總計,查詢花費74.4938秒)

+1

你有'lastlogon.username'上的索引嗎? – Clive

+0

你可以包括解釋計劃嗎?我期待它會回答克萊夫的問題,說沒有索引,並且正在執行全表掃描。 – MatBailie

+0

使用'lastlogon.username'是主鍵。而'messages'則有一個名爲'id'的單獨主鍵。 – ParoX

回答

0

我建議你添加一個索引在messages.title。然後嘗試再次運行查詢並測試性能。

+0

沒有真正幫助其他想法? – ParoX

+0

@BHare你的意思是說你得到的速度是相同的,還是說你的搜索效果並不好? –

+0

或多或少有相同的速度。 – ParoX

1

第一:更換標題密鑰,對標題+ ID的複合鍵

ALTER TABLE messages DROP INDEX title; 
ALTER TABLE messages ADD INDEX title (title, id); 

現在改變選擇:

SELECT m.* FROM messages m 
LEFT JOIN lastlogon l ON (l.username = m.title) 
WHERE l.username IS NULL 
-- GROUP BY m.id DESC -- faster replacement for distinct. I don't think you need this. 
LIMIT 1000; 

或者

SELECT m.* FROM messages m 
WHERE m.title NOT IN (SELECT l.username FROM lastlogon l) 
-- GROUP BY m.id DESC -- faster than distinct, I don't think you need it though. 
LIMIT 1000; 

另一個問題與緩慢是SELECT m.*部分。
通過選擇所有列,你迫使MySQL做額外的工作。
只選擇你需要的列:

SELECT m.title, m.name, m.email, ...... 

這將加快查詢也是如此。

有你可以用另一招:
替換一個截止日期的限制1000。

步驟1:在時間戳上添加一個索引(或任何你想用於截止的字段)。

SELECT m.* FROM messages m 
LEFT JOIN lastlogon l ON (l.username = m.title) 
WHERE (m.id > (SELECT MIN(M2.ID) FROM messages m2 WHERE m2.timestamp >= '2011-09-01')) 
    AND l.username IS NULL 
-- GROUP BY m.id DESC -- faster replacement for distinct. I don't think you need this. 
相關問題