2012-03-14 141 views
0

如何優化聯合和聯接查詢?是否有可能在聯盟之外移動一些聯接?優化聯合查詢中的聯接

(
    SELECT accounting.id, accounting.time, accounting.subaccount_id AS module_id, accounting.balance_invoice_id AS balance_id, accounting.currency_amount*-1 AS currency_amount, accounting.amount*-1 AS amount, enclosure.enc_id_, enclosure.txt, currency.name AS currency_name, IF(balance_invoice.amount, accounting.currency_amount*-1+SUM(balance_invoice.amount), accounting.currency_amount*-1) AS balance 
    FROM accounting 
    INNER JOIN enclosure ON enclosure.id=accounting.enc_id 
    LEFT JOIN currency ON currency.id=accounting.currency_id 
    LEFT JOIN balance_invoice ON balance_invoice.accounting_id=accounting.id 
    WHERE accounting.att_booked=1 
    GROUP BY accounting.id 
) 
UNION (
    SELECT accounting.id, accounting.time, accounting.subaccountoff_id AS module_id, accounting.balanceoff_invoice_id AS balance_id, accounting.currency_amount, accounting.amount, enclosure.enc_id_, enclosure.txt, currency.name AS currency_name, IF(balance_invoice.amountoff, accounting.currency_amount+SUM(balance_invoice.amountoff), accounting.currency_amount) AS balance 
    FROM accounting 
    INNER JOIN enclosure ON enclosure.id=accounting.enc_id 
    LEFT JOIN currency ON currency.id=accounting.currency_id 
    LEFT JOIN balance_invoice ON balance_invoice.accounting_id=accounting.id 
    WHERE accounting.att_booked=1 && accounting.type IN (0,1,2) 
    GROUP BY accounting.id 
) ORDER BY time DESC 
+0

您的查詢在SELECT子句中包含'GROUP BY accounting.id'子句和許多未聚合的字段。 MySQL允許它,但它不正確;檢查它,也許重寫你的查詢。 – Devart 2012-03-14 10:15:10

回答

1

事情是這樣的 -

SELECT 
    a.id, 
    a.time, 
    IF(a.acc_type = 1, a.subaccount_id, subaccountoff_id) AS module_id, 
    IF(a.acc_type = 1, a.balance_invoice_id, balanceoff_invoice_id) AS balance_id, 
    IF(a.acc_type = 1, a.currency_amount * -1, currency_amount) AS currency_amount, 
    IF(a.acc_type = 1, a.amount * -1, a.amount) AS amount, 
    e.enc_id_, 
    e.txt, 
    c.name AS currency_name, 
    IF(a.acc_type = 1, 
    IF(bi.amount, a.currency_amount * - 1 + SUM(bi.amount), a.currency_amount * -1), 
    IF(bi.amountoff, a.currency_amount + SUM(bi.amountoff), a.currency_amount) 
) AS balance 
FROM (
    SELECT 1 acc_type, a1.* FROM accounting a1 WHERE a1.att_booked = 1 
    UNION 
    SELECT 2 acc_type, a2.* FROM accounting a2 WHERE a2.att_booked=1 AND a2.type IN (0,1,2) 
) a 
INNER JOIN enclosure e 
    ON e.id = a.enc_id 
LEFT JOIN currency c 
    ON c.id = a.currency_id 
LEFT JOIN balance_invoice bi 
    ON bi.accounting_id = a.id 
GROUP BY 
    a.id 
ORDER BY 
    time DESC; 
+0

哇,這令人印象深刻。但速度更快嗎?如果是這樣,爲什麼? (這對我來說很有趣(也許我不是唯一的))) – 2012-03-14 08:52:48

+0

@Oivier Pons這兩個查詢都必須進行配置和比較(EXPLAIN SELECT)。我認爲這個查詢應該更快,我檢查了類似的例子。 – Devart 2012-03-14 10:03:44

0

這應該沒有UNION,太。我使用了幾個CASE語句。未經測試:

SELECT a.id, a.time 
     ,CASE WHEN a.type IN (0,1,2) THEN a.subaccountoff_id  ELSE a.subaccount_id  END AS module_id 
     ,CASE WHEN a.type IN (0,1,2) THEN a.balanceoff_invoice_id ELSE a.balance_invoice_id END AS balance_id 
     ,CASE WHEN a.type IN (0,1,2) THEN a.currency_amount  ELSE a.currency_amount*-1 END AS currency_amount 
     ,CASE WHEN a.type IN (0,1,2) THEN a.currency_amount  ELSE a.amount*-1   END AS amount 
     ,e.enc_id_, e.txt, c.name AS currency_name 
     ,CASE WHEN a.type IN (0,1,2) 
      THEN IF (b.amountoff, a.currency_amount + SUM(b.amountoff), a.currency_amount) 
      ELSE IF (b.amount, a.currency_amount*-1 + SUM(b.amount), a.currency_amount*-1) END AS balance 
FROM accounting a 
JOIN enclosure e ON e.id = a.enc_id 
LEFT JOIN currency c ON c.id = a.currency_id 
LEFT JOIN balance_invoice b ON b.accounting_id = a.id 
WHERE a.att_booked = 1 
GROUP BY a.id 
ORDER BY a.time DESC