2015-07-21 84 views
0

我試圖從數據庫表的集合中產生一個報告,我發現我寫的查詢超慢。我意識到在選擇查詢中使用多個子查詢會增加查詢完成所需的時間,因爲每行都需要對數據庫進行多個子查詢,但我能做些什麼來使查詢更快,更高效?MySQL選擇查詢中子選擇的效率

我試過在準備好的語句中包裝它,它沒有什麼作用,有沒有一種方法可以讓我更快地提取所需信息?

SELECT Contractor.id, 
Contractor.Unique_ID, 
Contractor.FName, 
Contractor.SName, 
Contractor.MIName, 
Contractor.NI_Number, 
Contractor.Address, 
Contractor.Phone_Main, 
Contractor.Phone_Mobile, 
Contractor.Email, 
Contractor.Bank_Name, 
Contractor.Bank_Account_Name, 
Contractor.Bank_Account_Sort_Code, 
Contractor.Bank_Account_Number, 
Contractor.DOB, 
Contractors.DateTime_Account_Created, 
Contractor.Payment_Frequency, 
Contractor.Saving_Tax_Pref, 
Contractor.Holiday_Savings_Pref, 
Contractor.UTR, 
Contractor.DateTime_Last_Logged_In, 
Contractor.Leaving_Date, 
Agency.Name, 
(
    SELECT ROUND(SUM(ContractorSavings.value - ContractorSavings.paidOutValue), 2) 
    FROM ContractorSavings 
    LEFT JOIN SavingsToPayJunction ON SavingsToPayJunction.SavingsId = ContractorSavings.id 
    WHERE fullyPaid = 0 
    AND ContractorSavings.type_id = 2 
    AND SavingsToPayJunction.ContractorId = Contractor.id 
) AS 'Tax_Saving_Balance', 
(
    SELECT ROUND(SUM(ContractorSavings.value - ContractorSavings.paidOutValue), 2) 
    FROM ContractorSavings 
    LEFT JOIN SavingsToPayJunction ON SavingsToPayJunction.SavingsId = ContractorSavings.id 
    WHERE fullyPaid = 0 
    AND ContractorSavings.type_id = 2 
    AND SavingsToPayJunction.ContractorId = Contractor.id 
) AS 'Holiday_Saving_Balance', 
(
    SELECT ROUND(SUM(Expense_Value),2) 
    FROM Contractor_Expenses 
    WHERE Contractor_ID = Contractor.id 
    AND authorised = 0 
)AS 'Expenses_Claimed', 
(
    SELECT ROUND(SUM(Expense_Value - amountAllocated),2) 
    FROM Contractor_Expenses 
    WHERE Contractor_ID = Contractor.id 
    AND authorised = 1 
    AND fullyAllocated = 0 
)AS 'Expenses_Authorised', 
(
    SELECT MAX(Contractor_Pay.Date_Earned) 
    FROM Contractor_Pay 
    WHERE Contractor_Pay.Contractor_ID = Contractor.Unique_ID 
)AS 'Last_Pay_Date' 
FROM Contractor 
LEFT JOIN Agency ON Agency.id = Contractor.Agency_ID 

笨拙的查詢轉儲道歉。我期待着你的迴應。

謝謝

*郵政的答案編輯*

對於那些關心時限等,答案降低我的查詢時間縮短從超過3:00分鐘到45秒。

+0

你使用corelated子查詢。對於主查詢中的每一行,您還將運行這些子查詢。所以對於'n'行'承包商'表,你實際上正在運行。 '1+(n * 6)'查詢。例如1000個承包商行,執行6001個查詢。 –

+0

是的,我知道。什麼是更好的方法? –

+0

許多這些子查詢根本不必是子查詢,例如'MAX(contractor_pay_umbrella)'。 –

回答

1

你可以在每個那些在FROM子句(與GRO​​UP BY Contractor_ID)子選擇的就加入他們了:

SELECT 
    Contractor.id, 
    Contractor.Unique_ID, 
    Contractor.FName, 
    Contractor.SName, 
    Contractor.MIName, 
    Contractor.NI_Number, 
    Contractor.Address, 
    Contractor.Phone_Main, 
    Contractor.Phone_Mobile, 
    Contractor.Email, 
    Contractor.Bank_Name, 
    Contractor.Bank_Account_Name, 
    Contractor.Bank_Account_Sort_Code, 
    Contractor.Bank_Account_Number, 
    Contractor.DOB, 
    Contractors.DateTime_Account_Created, 
    Contractor.Payment_Frequency, 
    Contractor.Saving_Tax_Pref, 
    Contractor.Holiday_Savings_Pref, 
    Contractor.UTR, 
    Contractor.DateTime_Last_Logged_In, 
    Contractor.Leaving_Date, 
    Agency.Name, 
    Tax_Saving_Balance.val as Tax_Saving_Balance, 
    Holiday_Saving_Balance.val as Holiday_Saving_Balance, 
    Expenses_Claimed.val as Expenses_Claimed, 
    Expenses_Authorised.val as Expenses_Authorised, 
    Last_Pay_Date.val as Last_Pay_Date 
FROM Contractor 
LEFT JOIN Agency ON Agency.id = Contractor.Agency_ID 
LEFT JOIN (
    SELECT SavingsToPayJunction.ContractorId, ROUND(SUM(ContractorSavings.value - ContractorSavings.paidOutValue), 2) as val, 
    FROM ContractorSavings 
    LEFT JOIN SavingsToPayJunction ON SavingsToPayJunction.SavingsId = ContractorSavings.id 
    WHERE fullyPaid = 0 
    AND ContractorSavings.type_id = 2 
    GROUP BY SavingsToPayJunction.ContractorId 
) as Tax_Saving_Balance ON Tax_Saving_Balance.ContractorId = Contractor.id 
LEFT JOIN (
    SELECT SavingsToPayJunction.ContractorId, ROUND(SUM(ContractorSavings.value - ContractorSavings.paidOutValue), 2) as val 
    FROM ContractorSavings 
    LEFT JOIN SavingsToPayJunction ON SavingsToPayJunction.SavingsId = ContractorSavings.id 
    WHERE fullyPaid = 0 
    AND ContractorSavings.type_id = 2 
    GROUP BY SavingsToPayJunction.ContractorId 
) as Holiday_Saving_Balance ON Holiday_Saving_Balance.ContractorId = Contractor.id 
LEFT JOIN (
    SELECT Contractor_ID, ROUND(SUM(Expense_Value),2) as val 
    FROM Contractor_Expenses 
    WHERE authorised = 0 
    GROUP BY Contractor_ID 
) as Expenses_Claimed ON Expenses_Claimed.Contractor_ID = Contractor.id 
LEFT JOIN (
    SELECT Contractor_ID, ROUND(SUM(Expense_Value - amountAllocated),2) as val 
    FROM Contractor_Expenses 
    WHERE authorised = 1 
    AND fullyAllocated = 0 
    GROUP BY Contractor_ID 
) as Expenses_Authorised ON Expenses_Authorised.Contractor_ID = Contractor.id 
LEFT JOIN (
    SELECT Contractor_ID, MAX(Contractor_Pay.Date_Earned) 
    FROM Contractor_Pay 
    GROUP BY Contractor_ID 
) as Last_Pay_Date ON Last_Pay_Date.Contractor_ID = Contractor.Unique_ID 
+0

我很感謝您的迴應,您的回答中的方法實際上比我當前的查詢更快。 出於興趣,你知道它爲什麼更快嗎? –

+1

FROM子句中的子查詢只運行一次(不相關) - 在您的查詢中它們更簡單,但每個承包商運行一次。在MySQL中,索引JOIN比相關子查詢更快,子查詢中的臨時表爲需要它們的字段獲得自動索引(從5.6我認爲)。 – Vatev