我有一个脚本,用于从客户那里获取与发票有关的数据。每个发票和订单都有一个将其与特定用户相关联的卡代码。有时,用户拥有多个与同一卡号相关联的用户帐户;在这种情况下,我将不得不使用最近使用过的用户帐户中的用户数据,这将通过子查询获得。
SELECT invoices.*,card.*,client.*
FROM `orders`
LEFT JOIN `invoices` ON `invoices`.`invoice_key` =`orders`.`invoice_key`
LEFT JOIN `cards` `card` ON `card`.`card_code` = `orders`.`card_code`
LEFT JOIN `users` `client` ON `client`.`id` = (
SELECT MIN(c.id) c_id FROM `users` `c`
WHERE (`card`.`card_code` COLLATE utf8_unicode_ci) = `c`.`card_code`
AND `c`.`active` = 1 ORDER BY `c`.`last_login` DESC LIMIT 1
)
WHERE `orders`.`date` BETWEEN %start_date% AND %end_date%
这很好,但是后来我实现了一个系统,在该系统中,用户可以使用多个卡代码;为了解决这个问题,我创建了另一个将用户链接到卡的表(用户卡)。并非所有用户都在此处输入信息。大多数只需要使用其默认卡代码。
SELECT invoices.*,card.*,client.*
FROM `orders`
LEFT JOIN `invoices` ON `invoices`.`invoice_key` =`orders`.`invoice_key`
LEFT JOIN `cards` `card` ON `card`.`card_code` = `orders`.`card_code`
LEFT JOIN `usercards` ON `usercards`.`card_code` = `card`.`card_code`
LEFT JOIN `users` `client` ON (`usercards`.`user_id` IS NOT NULL
AND `client`.`id` = `usercards`.`user_id`)
OR (`usercards`.`user_id` IS NULL AND `client`.`id` = (
SELECT MIN(c.id) c_id FROM `users` `c`
WHERE (`card`.`card_code` COLLATE utf8_unicode_ci) = `c`.`card_code`
AND `c`.`active` = 1 ORDER BY `c`.`last_login` DESC LIMIT 1)
)
WHERE `orders`.`date` BETWEEN %start_date% AND %end_date%
但是,这导致查询运行很多较慢-几分钟之前不到一秒钟。我知道它与子查询有关(如果我忽略了那一部分,只是简单地连接到该client.card_code = card.card_code的所有地方,它就可以快速运行,但是当然数据是错误的),但是我无法确定为何我看不到有任何迹象表明需要处理的数据呈指数增长。
有很多订单和发票,但是用户卡中只有很少的条目。另外,usercards.card_code是唯一索引。
答案 0 :(得分:1)
我有太多问题无法直接回答。
OR
是性能杀手。该 可以很好地转换为UNION
。如果是这样,IS [not] NULL
子句也许可以同时简化。MIN
和LIMIT 1
相互斗争。我怀疑您应该摆脱MIN
。LEFT
。usercards
索引提示。usercards.user_id IS NULL
似乎是一个新条件;不会改变结果吗?card_code
列之一的排序规则以匹配另一列。您所拥有的要么打败了索引的使用,要么放慢了速度。JOIN
(假设不需要LEFT
)来开始。INDEX(card_code, active, last_login, id)
-按此顺序。有关更多讨论,请提供
SHOW CREATE TABLE -- for each table
EXPLAIN SELECT -- for each query being discussed