2010-11-18 259 views
1

我有一個存儲導入信息的數據庫表。爲簡單起見,它是這樣的:MySQL查詢優化

CREATE TABLE `data_import` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, 
`amount` DECIMAL(12,2) NULL DEFAULT NULL, 
`payee` VARCHAR(50) NULL DEFAULT NULL, 
`posted` TINYINT(1) NOT NULL DEFAULT 0, 
PRIMARY KEY (`id`), 
INDEX `payee` (`payee`) 
) 

我也有存儲進口規則的表:

CREATE TABLE `import_rules` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
`search` VARCHAR(50) NULL DEFAULT NULL, 
PRIMARY KEY (`id`), 
INDEX `search` (`search`) 
) 

的想法是,每個進口交易,查詢需要嘗試找到一個匹配規則 - 這個匹配是在data_import.payee和import_rules.seach字段上完成的。因爲這些都是varchar字段,所以我對它們進行了索引,希望能夠加快查詢速度。

這是我到目前爲止,這似乎工作正常。儘管比我希望的要慢。

SELECT i.id, i.payee, i.amount, i.posted r.id, r.search 
FROM import_data id 
LEFT JOIN import_rules ir on REPLACE(i.payee, ' ', '') = REPLACE(ir.search, ' ', '') 

一兩件事,上面的查詢並不滿足,就是如果import_data.posted = 1,那麼我不需要找到該行的規則 - 這可能停止查詢加盟在那個特定的行?同樣,如果收款人爲空,那麼它也不應嘗試加入。

我還有其他方法可以優化嗎?我意識到做文本連接並不理想......不確定是否有更好的方法。

回答

2

在連接上使用REPLACE()可能會破壞索引,因爲它具有字段中值的索引,而不是REPLACE()後的修改值。

至於未加入,您已經在使用LEFT JOIN,因此,不匹配的連接將導致import_rules字段爲NULL;你應該可以添加WHERE子句來強制這個。

3

我強烈建議盡你所能去擺脫REPLACE s在那JOIN。在連接的兩側使用REPLACE完全消除了在任一表上使用索引的能力。

假設你可以擺脫REPLACE S的(通過清洗現有的數據和/或新數據):

  • 如果需要加入文本 列,使用每個 單字節字符字符集,如果你的應用程序 允許它(對於更小/更快的索引)。
  • 充分利用NVARCHAR(N)小 ,你可以,因爲它會影響到指數的側 (或者可以說,使用指數 前綴)。
  • 我想你想的import_rules UNIQUEsearch指數 - 那麼你一定要只 要得到每行1個結果中返回的 import_data

可以拋出一個AND如果你想強制你的'不參加這種情況'的規則,你的WHERE條款。

LEFT JOIN import_rules ir ON id.payee=ir.search AND id.posted != 1