我有一个存储导入信息的数据库表。为简单起见,它类似于:
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,那么我不需要为该行找到规则 - 是否可以停止对该特定行的查询连接?同样,如果收款人为空,则也不应尝试加入。
还有其他方法可以优化它吗?我意识到进行文本连接并不理想……不确定是否有更好的方法。
最佳答案
我强烈建议您尽一切可能摆脱 JOIN
中的 REPLACE
。在连接的两侧使用 REPLACE
完全消除了在任一表上使用索引的能力。
假设您可以摆脱 REPLACE
(通过清理现有数据和/或新数据):
- 如果您需要加入文本 列,每个使用一个字节 字符集,如果你申请 允许它(对于更小/更快的索引)。
- 使
VARCHAR(N)
中的N
尽可能小 尽你所能,因为它会影响侧面 索引的(或者可以说,使用索引 前缀)。 - 我想你想做
search
import_rules
索引UNIQUE
——那么你确定只 将得到每行返回的 1 行结果导入数据
如果您想执行“在这种情况下不加入”规则,您可以将 AND
放入您的 WHERE
子句中。
LEFT JOIN import_rules ir ON id.payee=ir.search AND id.posted != 1
关于sql - MySQL查询优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4219216/