我有一个存储导入信息的数据库表。为简单起见,它的内容如下:
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,那么我不需要为该行找到规则 - 是否可以停止查询加入该特定行?同样,如果收款人为空,则不应尝试加入。
还有其他方法可以优化吗?我意识到做文本连接并不理想......不确定是否有更好的方法。
答案 0 :(得分:3)
我强烈建议您尽一切努力摆脱REPLACE
中的JOIN
。在连接的两端使用REPLACE
完全消除了在任一表上使用索引的能力。
假设你可以摆脱REPLACE
(通过清理现有数据和/或新数据):
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子句来强制它。