2010-11-18 205 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