2013-07-13 325 views
1

我想利用您对下面的查询思路:查询花费太多时间

select a.expense_code, a.expense_date, a.expense_supplier_code, b.supplier_name, a.expense_discount, a.expense_payment_method, a.expense_payment_transfer_to, a.expense_advance, a.expense_status, 
          sum(c.expense_item_buy_price * c.expense_item_quantity) , d.account_name, a.expense_counter, a.expense_type, a.expense_saving_type, a.expense_payment_transfer_from 
          from expense_data a, supplier_data b, expense_item c, tree_data d 
          where a.expense_supplier_code = b.supplier_code and a.expense_payment_transfer_to= d.account_code 
          and a.expense_counter = c.expense_counter 
          and a.expense_date between '2013-01-01' and '2014-01-01' and a.expense_status = 0 or a.expense_status = 2 group by (a.expense_counter); 

这个查询花费如此多的时间,即使在EXPENSE_DATA表中,有四个指标:

1- Expense_code. 
2- expense_user_id 
3- expense_supplier_code 
4- expense_payment_transfer_from 

我不知道为什么需要这么多时间是因为两次连接太多或者是因为太多的连接。你能建议吗?

+2

你看看运算符优先级了吗?并具有比或更高的优先级。最后,你写'a.expense_status = 0或a.expense_status = 2'。我认为这应该在括号中,或者你应该把它改成'(0,2)'中的'a.expense_status',除非你实际上意味着任何具有状态2的行应该被返回,而不管其他条件如何。 – GolezTrol

+1

运行'EXPLAIN EXTENDED'+ YourQuery代码;并将结果发布到上面的问题中,否则我们不知道表的大小,类型,索引是否用于执行查询等。 – cerd

+0

不要忘记使用执行计划。 –

回答

-1

你必须把OR条件括号:

SELECT a.expense_code, 
    a.expense_date, 
    a.expense_supplier_code, 
    b.supplier_name, 
    a.expense_discount, 
    a.expense_payment_method, 
    a.expense_payment_transfer_to, 
    a.expense_advance, 
    a.expense_status, 
    SUM(c.expense_item_buy_price * c.expense_item_quantity), 
    d.account_name, 
    a.expense_counter, 
    a.expense_type, 
    a.expense_saving_type, 
    a.expense_payment_transfer_from 
FROM expense_data a, 
    supplier_data b, 
    expense_item c, 
    tree_data d 
WHERE a.expense_supplier_code = b.supplier_code 
    AND a.expense_payment_transfer_to = d.account_code 
    AND a.expense_counter = c.expense_counter 
    AND a.expense_date BETWEEN '2013-01-01' AND '2014-01-01' 
    AND (a.expense_status = 0 OR a.expense_status = 2) 
GROUP BY a.expense_counter; 
+0

这是一种改变行为而不是加快速度的功能变化(虽然它可能会意外)。 – GolezTrol

+0

它会加快速度 - 通过删除这个巨大的笛卡儿连接AxBxCxD!这绝对是一个错误,而不是故意的情况。 –

+0

是的,但通过改变结果加快速度通常是不期望的,除非它实际上是一个错误,这只是一个猜测。你至少应该提到你改变了查询的行为。 – GolezTrol

0

为了加快速度,你可能想尝试使你加入的列组合的组合索引。该索引可能比您现在使用的四个单独索引更有用,尽管您仍然可以保留这些索引。除了这四个字段之外,您甚至可以通过将status和/或expense_data添加到索引来进行试验。

+0

他需要为表格解释扩展和描述,甚至覆盖索引是毫无意义的,如果排序不正确或者类型/长度方差,空间/时间浪费在阻塞上。 – cerd

2

可能是您的where子句包含逻辑错误。 看看最后一行(最后OR条件):

where 
    .... 
    and a.expense_counter = c.expense_counter 
    and a.expense_date BETWEEN '2013-01-01' AND '2014-01-01' 
    and a.expense_status = 0 
    or a.expense_status = 2 

,意思是“取枣等之间以及与状态0记录,或采取的所有记录以状态2

+0

非常好,从你兄弟它解决了我的问题 – user2103335

+1

欢迎来到堆栈溢出。当有人的回答证明对您有帮助时,请点击绿色大纲复选标记接受它。提升你认为有用的答案也很有礼貌。 –

0

它要重新编码使连接更清晰(并删除大量加入其中,如果费用地位的所有表都加入)给出: -

SELECT a.expense_code, 
    a.expense_date, 
    a.expense_supplier_code, 
    b.supplier_name, 
    a.expense_discount, 
    a.expense_payment_method, 
    a.expense_payment_transfer_to, 
    a.expense_advance, 
    a.expense_status, 
    SUM(c.expense_item_buy_price * c.expense_item_quantity) , 
    d.account_name, 
    a.expense_counter, 
    a.expense_type, 
    a.expense_saving_type, 
    a.expense_payment_transfer_from 
FROM expense_data a, 
INNER JOIN supplier_data b ON a.expense_supplier_code = b.supplier_code 
INNER JOIN expense_item c ON a.expense_counter = c.expense_counter 
INNER JOIN tree_data d ON a.expense_payment_transfer_to= d.account_code 
WHERE a.expense_date BETWEEN '2013-01-01' AND '2014-01-01' 
AND a.expense_status = 0 OR a.expense_status = 2 
GROUP BY (a.expense_counter); 

看,这是重要的,你对supplier_data上supplier_code有一个索引表,expense_item表上的expense_counter索引以及tree_data表上的account_code上的索引。

我怀疑你并不是真的想要将费用状态为0并且该范围内的费用日期与费用状态2的任何记录无关地归还,因此以下可能是您想要的:

SELECT a.expense_code, 
    a.expense_date, 
    a.expense_supplier_code, 
    b.supplier_name, 
    a.expense_discount, 
    a.expense_payment_method, 
    a.expense_payment_transfer_to, 
    a.expense_advance, 
    a.expense_status, 
    SUM(c.expense_item_buy_price * c.expense_item_quantity) , 
    d.account_name, 
    a.expense_counter, 
    a.expense_type, 
    a.expense_saving_type, 
    a.expense_payment_transfer_from 
FROM expense_data a, 
INNER JOIN supplier_data b ON a.expense_supplier_code = b.supplier_code 
INNER JOIN expense_item c ON a.expense_counter = c.expense_counter 
INNER JOIN tree_data d ON a.expense_payment_transfer_to= d.account_code 
WHERE a.expense_date BETWEEN '2013-01-01' AND '2014-01-01' 
AND a.expense_status IN (0, 2) 
GROUP BY (a.expense_counter);