2012-09-15 33 views
0

專欄中,我有2個表中選擇行:其中類似字典裏的單詞

詞典 - 包含大約36000字

CREATE TABLE IF NOT EXISTS `dictionary` (
    `word` varchar(255) NOT NULL, 
    PRIMARY KEY (`word`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

DATAS - 大約100,000行

CREATE TABLE IF NOT EXISTS `datas` (
    `ID` int(11) NOT NULL AUTO_INCREMENT, 
    `hash` varchar(32) NOT NULL, 
    `data` varchar(255) NOT NULL, 
    `length` int(11) NOT NULL, 
    `time` int(11) NOT NULL, 
    PRIMARY KEY (`ID`), 
    UNIQUE KEY `hash` (`hash`), 
    KEY `data` (`data`), 
    KEY `length` (`length`), 
    KEY `time` (`time`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=105316 ; 

一載想要以某種方式選擇來自datas的所有行,其中列data包含1個或更多的單詞。

我理解,這是一個很大的要求,就需要在每一個組合可以匹配所有這些行在一起,所以它需要的最佳優化。

我曾嘗試下面的查詢,但它只是掛起的年齡:

SELECT  `datas`.*, `dictionary`.`word` 
FROM  `datas`, `dictionary` 
WHERE  `datas`.`data` LIKE CONCAT('%', `dictionary`.`word`, '%') 
AND   LENGTH(`dictionary`.`word`) > 3 
ORDER BY `length` ASC 
LIMIT  15 

我也曾嘗試類似上面左連接東西,對指定的LIKE語句子句。

+0

@eggyal:謝謝,但我嘗試過,並沒有工作。根據這篇文章的答案(http://stackoverflow.com/questions/10465758/subquery-incorrect-arguments-to-against-using-mysql),'AGAINST'必須是一個文字字符串。 – Drahcir

+2

「即使是15行限制」也與您的查詢不相關,因爲限制只能在結果確定和排序後進行。 – Eddy

+0

@Eddy:好的,謝謝 – Drahcir

回答

1

這其實不是一個簡單的問題,你想什麼來執行被稱爲全文檢索和關係數據庫不適合這樣的任務的最佳工具。如果這是某種核心功能,請考慮使用專門用於此類操作的解決方案,如Sphinx Search Server

如果這不是一個「關鍵任務」系統,你可以用別的東西嘗試。我可以看到,datas.data列並不長,因此您可以創建一個專用於您的任務的結構,並在操作使用期間保持它不變。富勒例如,創建表:

dictionary_datas (
    datas_id FK (datas.id), 
    word FK (dictionary.word) 
) 

現在,只要你插入,刪除或只需修改DATAS或字典表更新dictionary_datas將有信息這datas_id包含哪些單詞(基本上是多對多的關係)。當然,它會降低你的性能,所以如果你的系統有很高的事務負載,你必須這樣做。例如,在每天早晨03:00放置一個Cron Job,並將其實現。爲了簡化該任務可以添加標誌到TO_CHECK DATAS表,僅針對具有有1的那些記錄的數據具體化(你具體化後dictionary_datas你的值切換到0)。請記住在更新DICTIONARY表後刷新整個DATAS表。在數據處理方面,36 000和100 000不是大數字。

一旦你有了這個表你可以查詢它想:

SELECT datas_id, count(*) AS words_num FROM dictionary_datas GROUP BY datas_id HAVING count(*) > 3; 

爲了加快查詢(和尚未減緩它的更新),您可以創建一個綜合指數在其列datas_id,字(以就是那個順序)。如果您決定刷新數據periodicaly刷新前刪除索引,比刷新數據,刷新後finaly創建索引 - 這樣會更快。

+0

謝謝,保持專用結構的想法很好。數據表包含來自每天晚上收集並通過「加載數據」插入的Web服務的數據。我設法將查詢時間縮短到現在約6分鐘,這很好(因爲它只需要運行一次)。 – Drahcir

+0

有沒有我建議的結構縮小範圍?我想你在DATAS表中的數據會增長,因此它會放慢速度。如果您實施任何增量方法(例如每晚只更新更改/插入的行),您將能夠或多或少地控制處理時間。 – WojtusJ

+0

我在做主查詢之前通過創建別名表來縮小範圍(因此減少了與第一個匹配的記錄數(長度> 3是其中之一))。數據表只用過一次,所有數據每天都是新鮮的。 – Drahcir

0

我不知道如果我理解你的問題,但我認爲這可能是一個解決方案。另外,我認爲人們不喜歡正則表達式,但是這對我選擇其值超過1個字的列是有效的。

SELECT * FROM WHERE數據REGEXP 「([A-Z])+」

+0

謝謝,但它不能解決問題。單詞必須來自問題中定義的字典表,該表只包含與任務相關的某些關鍵字。 – Drahcir

0

你有沒有試過這種DATAS?

select * 
from dictionary, datas 
where position(word,data) > 0 
; 

這是非常低效的,但可能對你來說足夠好。 Here is a fiddle

爲了獲得更好的性能,你可以嘗試在你的文本列DATA放置text search index,然後使用CONTAINS功能,而不是POSITION