2017-10-10 112 views
1

我的情況是這樣的: 我有一張表(phrases),有大約500,000個條目。每個條目就像一個短語:Mysql匹配短語對句短語

Beating Around the Bush 
Burst Your Bubble 
Cry Wolf 
Curiosity Killed The Cat 

而且我有另一個表(full_sen)4000個條目,每個條目在它短語句子。

我想匹配full_sen表來找出哪些句子中有短語。

我需要頻繁運行,因爲兩個表都會定期有新的條目,而且我需要能夠快速運行的東西。

最簡單的查詢是走在50萬臺,並做了LIKE %phrase%搜索 對full_sen表,但需要永遠...

我不介意結合PHP或者Python是否會有所幫助;它不一定只是一個查詢。

full_sen CREATE TABLE `full_sen` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL, 
`sku` varchar(21) COLLATE utf8_unicode_ci DEFAULT NULL, 
`user_id` int(11) NOT NULL, 
PRIMARY KEY (`id`), 
UNIQUE KEY `full_sen_sku_670bbe26026365f4_uniq` (`sku`), 
KEY `full_sen_e8701ad4` (`user_id`), 
CONSTRAINT `full_sen_user_id_295adcd84efdd880_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=5232 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

phrases CREATE TABLE `phrases` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`date` date NOT NULL, 
`serial_number` varchar(20) NOT NULL, 
`title` varchar(250) NOT NULL, 
`status_number` smallint(5) unsigned, 
PRIMARY KEY (`id`), 
UNIQUE KEY `serial_number` (`serial_number`), 
KEY `phrases_status_number_5f42a821_uniq` (`status_number`), 
FULLTEXT KEY `title` (`title`) 
) ENGINE=InnoDB AUTO_INCREMENT=632144 DEFAULT CHARSET=latin 

姓名和職位是我所談論的領域。

謝謝。

+1

更新你所做的工作(代碼或查詢) –

+0

請顯示確切的表格定義,以便我們可以看到列的長度和數據類型(在SHOW CREATE TABLE ...的輸出後面)。 – Binarus

+0

@binarus,POSTED –

回答

1

您可以通過兩種方法來提高性能:預計算和使用索引。他們每個人都會大幅提高性能,甚至可以將它們結合起來。因此,讓我們一起來看看:

正如你已經自己找到了,最簡單的解決方法是遍歷phrases表的每一行做了LIKE %phrase%full_sen表(旁註:你寫LIKE %sentence%,但我認爲這是一個錯字 - 也許我會後來編輯你的文章)。

但實際上,沒有必要這樣做。

與名稱phrase_sentence_pairs創建一個第三表,含有柱ID(這僅僅是行ID /主鍵),列phrase_id和列sentence_id。必須對phrase_idsentence_id編制索引(非唯一)。當然,在開始時你必須根據下面解釋的算法填寫你已經擁有的所有數據。這可能需要很長時間,但不應該緊,因爲它必須一次完成一次

現在,當一個新短語添加到phrases表中時,您只需要掃描整個full_sen表中的那個短語。每次將該短語包含在句子中時,都會向phrase_sentence_pairs表添加新行,以便phrase_id存儲來自phrases表的新短語的ID,並且sentence_id存儲full_sen表的當前匹配行的ID

同樣,當一個新句子被添加到full_sen表中時,循環遍歷phrases表,並檢查每一行是否包含在新句子中的短語。如果是的話,你添加一個新行phrase_sentence_pairs表,以便sentence_id存儲新句子從full_senIDphrase_id存儲phrases表的匹配當前行的ID。

在性能方面,這會導致以下情況:

你不會SELECT直接從phrasesfull_sen表了。例如,當您想要查找給定短語的所有句子時,首先從phrases表中獲取該短語的ID,然後從匹配的phrase_sentence_pairs表中選擇所有記錄。

相反的動作(將所有短語提取到某個句子)以相同的方式工作。

phrase_sentence_pairs表中選擇將比以前閃電更快。這主要是因爲數據庫現在正在比較數字而不是部分匹配的字符串,並且(更重要),因爲可以使用索引來完成這個SELECT

另一方面,插入會更慢。但是總體性能增益仍然很高:

我們假設從phrase_sentence_pairs開始的SELECT所採用的時間可以忽略不計(這種假設在這種情況下是可以的),所以我們不會進一步考慮它。使用以前的版本,每次選擇時必須對500K * 4K記錄進行LIKE字符串比較。

相反,你現在有插入一個新的詞組(這意味着500K其中先要進行掃描行方面的因素(!))時做4K記錄LIKE字符串比較,並在500K記錄時插入一個新的句子(這意味着對於必須掃描的行而言,因子爲4K)。

即使我們考慮到我們現在必須在插入短語或句子時寫入兩個表而不是一個,並且寫入索引列當然比寫入非索引列要慢,我認爲這是是一個非常好的交易。

如果插入仍然不夠快,還有另一個技巧可以大大提高掃描速度。但在詳細說明這一點之前,請首先嚐試我上面的建議並報告性能增益(最好在問題結束時添加它)。

最後一點,請注意,一個UPDATEphrasesfull_sen表必須引起幾乎相同的代碼來運行爲INSERT,並且你必須在DELETEphrasesfull_sen表後運行相應的代碼。