MySQL查询优化

时间:2010-11-18 20:24:24

标签: sql mysql optimization performance

我有一个存储导入信息的数据库表。为简单起见,它的内容如下:

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 个答案:

答案 0 :(得分:3)

我强烈建议您尽一切努力摆脱REPLACE中的JOIN。在连接的两端使用REPLACE完全消除了在任一表上使用索引的能力。

假设你可以摆脱REPLACE(通过清理现有数据和/或新数据):

  • 如果您需要加入文字 列,每个使用一个字节 字符charset如果您申请 允许它(对于更小/更快的索引)。
  • N中的VARCHAR(N)缩小 尽你所能,因为它会影响到一方 索引(或可以说是使用索引) 前缀)。
  • 我想你想做的 search上的import_rules索引 UNIQUE - 那么你肯定只会 将获得每行返回1行结果 import_data

如果您要强制执行“不加入此案例”规则,则可以在AND条款中添加WHERE

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

答案 1 :(得分:2)

在连接上使用REPLACE()可能会破坏索引,因为它具有字段中值的索引,而不是REPLACE()之后的修改值。

至于不加入,您已经在使用LEFT JOIN,因此不匹配的连接将导致import_rules字段为NULL;你应该能够添加WHERE子句来强制它。