我有一个相当复杂的查询,需要1-2分钟才能执行。有没有办法改善执行时间?
以下是查询:
select o.orders_id, o.customers_id, o.customers_name, s.orders_status_name,
ot.text as order_total, ot.value, DATEDIFF(NOW(), payment_data_read_status) as numDaysLeft,
( SELECT ifnull(sum(op.paid_amount), 0)
from orders_payment op
where op.orders_id=o.orders_id
AND op.confirm_payment='1'
) as paid_total
from orders o, orders_total ot, orders_status s
where o.orders_id = ot.orders_id
and ot.class = 'ot_total'
and o.orders_status = s.orders_status_id
and s.language_id = '1'
AND ROUND(ot.value,2) != ROUND(
( SELECT ifnull(sum(op.paid_amount),0)
from orders_payment op
where op.orders_id=o.orders_id
AND op.confirm_payment='1'
), 2)
订单中的记录数= 7321
orders_total = 22167
中的记录数orders_payment中的记录数量= 12038
orders_status = 9中的记录数
orders_id列是订单表中的自动增量。首先我想在订单表中索引orders_id列,但因为它是主要的,所以我认为它不会起作用。
EDITS 错误
答案 0 :(得分:1)
我发现嵌套查询不一定是坏的,但我尽量避免将它们放在选择列表中。这是我的建议:
select
o.orders_id,
o.customers_id,
o.customers_name,
s.orders_status_name,
ot.text as order_total,
ot.value,
datediff(now(), payment_data_read_status) as numdaysleft,
ifnull(op.paid_total, 0) paid_total
from
orders o
join
orders_total ot
on o.orders_id = ot.orders_id
join
orders_status s
on o.orders_status = s.orders_status_id
left outer join
(
select
orders_id,
sum(ifnull(paid_amount, 0)) as paid_total
from
orders_payment
where
confirm_payment = '1'
group by
orders_id
) op
on
op.orders_id = o.orders_id
where
ot.class = 'ot_total' and
s.language_id = '1' and
round(ot.value,2) != round(ifnull(op.paid_total, 0), 2);
我认为这会让优化者有更好的机会做好工作。
请注意,我已将"组放在"在" op"的内部查询中。如果没有这个,我想你可能会欺骗优化器为每个结果行运行这个查询而不只是一次。
使用您拥有的卷,您不需要任何索引;他们可能会让事情变得更糟而不是更好,但要测试它,看看会发生什么。
我还没有能够测试我的建议,但如果你提供创建表脚本和一些数据,我会这样做。如果我在查询中输入任何拼写错误,请道歉。
答案 1 :(得分:0)
类似于Ron Ballard的回答,但是在子查询中进行舍入,并切换到显式连接语法: -
SELECT o.orders_id,
o.customers_id,
o.customers_name,
s.orders_status_name,
ot.text as order_total,
ot.value,
DATEDIFF(NOW(), payment_data_read_status) as numDaysLeft,
sub0.paid_amount_sum as paid_total
FROM orders o
INNER JOIN orders_total ot ON o.orders_id = ot.orders_id
INNER JOIN orders_status s ON o.orders_status = s.orders_status_id
INNER JOIN
(
SELECT orders_id,
COALESCE(SUM(op.paid_amount),0) AS paid_amount_sum,
ROUND(COALESCE(SUM(op.paid_amount),0), 2) AS paid_amount_sum_rounded
FROM orders_payment op
WHERE op.confirm_payment = '1'
GROUP BY orders_id
) sub0
ON sub0.orders_id = o.orders_id
WHERE ot.class = 'ot_total'
AND s.language_id = '1'
AND ROUND(ot.value,2) != sub0.paid_amount_sum_rounded
答案 2 :(得分:0)
233结果vs 55的问题可能是测试... != ...
,其中一个可能是NULL
。返回NULL
,将其视为false,因此就像=
。
解决这个问题的一种方法是添加
AND sub0.paid_amount_sum_rounded IS NOT NULL
所需索引:
o: INDEX(orders_status, orders_id) -- in this order
ot: INDEX(class, orders_id) -- in either order
远离这个和其他答案:
JOIN ... ON ...
语法。 (这是为了清楚;它对性能没有影响。)LEFT JOIN
结果的NULL
和子查询。WHERE
。