2011-03-17 197 views
0

我有一個相當大的查詢,運行速度非常慢。一開始花了大約15分鐘。然後我添加了所有適當的索引,並將其降至30秒。這是昨天。今天,我添加了2個新的連接,並且實際上將幾個LEFT JOIN改爲INNER,現在它需要運行20多分鐘。MySQL查詢運行非常緩慢

這是查詢的EXPLAIN。我上傳了一個Excel文件到SkyDrive,結果如下:http://cid-a32b31fdac0efced.office.live.com/view.aspx/mysqlexplain.xlsx

你會在這裏看到有一個表mwd,它表示沒有密鑰。我檢查過這張表,它的確有相應的索引。但是,這並不是我加入聯盟的表,並且昨天運行良好。

新加入我創建可以在線路28和29

任何幫助將不勝感激可見。

編輯:編輯:我再次運行查詢沒有從mwd表的字段,即。 BIR3Mdealer_codecountry_codedsm_dealer_numberlocation_numberdms_typesequence_numberversion_no_edrid_dms_typeversion_no_dmsversion_date_dms,現在在4秒運行! (它仍然在加入這張桌子)

我知道它找不到mwd的密鑰,即使在正確的字段中有一個索引,那麼我該怎麼做呢?

編輯:沒有真的想發佈查詢,工作的東西。但這是加入的第一部分,這是造成延誤的原因。這是很長......

SELECT mwd.dealer_code AS "BIR3M", 
    vm.chassis_number AS "VIN", 
    vm.Vehicle_ID, 
    vm.Registration, 
    COALESCE(vm.After_sale_type, "") AS "After Sales Type", 
    COALESCE(vm.Fabrication_No, "") AS "Fabrication No", 
    I.created_date AS "InvoiceDate", 
    I.department_id, 
    COALESCE(C.claim_number, "") AS "Intervention ID", 
    wb.booking_id AS "Booking ID", 
    wb.booking_date_time AS "Booking Date", 
    iba.account AS "Account Number", 
    acc.account_name AS "Account Description", 
    ibi.warranty_percentage AS "Payee Responsibility %", 
    IF(I.iscredit = 1, I.invoice_number, COALESCE(I2.invoice_number, "")) AS "Invoice Number", 
    IF(I.iscredit = 1, COALESCE(I2.invoice_number, "") , "") AS "Original Invoice Number", 
    "" AS "Part Reference", 
    "" AS "Part Description", 
    ibi.Booking_Time AS "Quantity", 
    0 AS "Cause Indicator", 
    "" AS "Stock Status", 
    ROUND(
      (
       CASE WHEN iBI.Claimed_Flag = 1 THEN (ibi.booking_time * ibi.warranty_labour_rate) 
        #(iBI.Claimed_Value * iBI.warranty_Labour_Rate) 
       WHEN iBi.Claimed_Flag = 0 THEN ibi.booking_time 
        #(iBI.Claimed_Value) 
       END 
      ) # End 
      * CASE WHEN I.iscredit = 1 THEN -1 ELSE 1 END 
     ,2) AS "RetailPrice", 
    ibia.discount AS "Discount Rate", 
    0.00 AS "Surcharge Rate", 
    ROUND(
    ibi.Booking_Time * ibi.warranty_labour_rate * (1 - ibia.discount/100) * 
     COALESCE(mwc.commercial_cont, 100)/100 , 2) 
    AS "Cost Before Tax", 
     iba.account AS "Account", 
    CASE 
     WHEN ibi.warranty_percentage > 0 THEN "Warranty" 
     WHEN act.generic_type = 0 THEN "External" 
     WHEN act.generic_type = 1 THEN "Vehicle" 
     WHEN act.generic_type = 2 THEN "Internal" 
     WHEN act.generic_type = 3 THEN "Non Productive" 
    END AS "AccountType", 
    ibi.booking_time AS "Labour Time", 
    ibi.warranty_labour_rate AS "Hourly Rate", 
    0.00 AS "VAT Rate", 
    0.00 AS "VAT Total", 
    IBI.id AS "Invoice Booking Item ID", 
    IBI.operation_code AS "OPECOD", 
    IBI.job_description AS "Description", 
    CASE WHEN i.iscredit = 1 THEN 9 ELSE 0 END AS "Accounts Allocation", 
    COALESCE(mwc.contract_card_no, "") AS "Contract Card No", 
    COALESCE(mwc.vehicle_mileage, "") AS "Mileage", 
    COALESCE(mwc.delivery_date, "") AS "Delivery Date", 
    COALESCE(mwc.vo_number, "") AS "VO Number", 
    COALESCE(mwc.expense_code, "") AS "Expense Code", 
    COALESCE(mwc.catalog_function, "") AS "Catalog Function", 
    COALESCE(mwc.customer_complaint, "") AS "Customer Complaint", 
    COALESCE(mwc.commercial_cont, 100) AS "Commercial Contribution", 
    COALESCE(mwc.ots_otc_no, "") AS "OTS/OTC No", 
    COALESCE(mwc.supplier_code, "") AS "Supplier Code", 
    COALESCE(mwc.paint_code, "") AS "Paint Code", 
    COALESCE(mwc.off_road_breakdown, "") AS "Off Road Breakdown", 
    COALESCE(mwc.approval_no, "") AS "Approval No", 
    COALESCE(mwc.assistance_number, "") AS "Assistance Number", 
    COALESCE(mwc.customer_complaint_comment, "") AS "Customer Complaint Comment", 
    wb.booking_id AS "Repair Order Number", 
    wb.booking_date_time AS "Repair Order Date", 
    mwd.dealer_code, 
    mwd.country_code, 
    mwd.dsm_dealer_number, 
    mwd.location_number, 
    mwd.dms_type, 
    mwd.sequence_number, 
    mwd.version_no_edr, 
    mwd.id_dms_type, 
    mwd.version_no_dms, 
    mwd.version_date_dms, 
    COALESCE(mwc.customer_satisfied, "") AS "Customer Satisfied", 
    COALESCE(mwc.dealer_satisfied, "") AS "Dealer Satisfied", 
    COALESCE(mwc.parts_invoice_no, "") AS "Parts Invoice Number", 
    "" AS "Parts Type", 
    "" AS "Packaging Code", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN "P" 
     WHEN br.Business_ID IS NOT NULL THEN "S" 
     WHEN d.CODE IS NOT NULL THEN "S" 
    END AS "Customer Type", 
    "P" AS "Customer Vehicle Relation", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN cr.Surname 
     WHEN br.Business_ID IS NOT NULL THEN br.Company_Name 
     WHEN d.CODE IS NOT NULL THEN d.Description 
    END AS "Surname/Corporate Name", 
    "GB" AS "Language", 
    COALESCE(cr.Surname, "") AS "Second Name", 
    COALESCE(cr.Forename, "") AS "First Name", 
    COALESCE(cr.Date_Of_Birth, "") AS "DOB", 
    COALESCE(cr.Title, "") AS "Title", 
    COALESCE(vm.Registration_Date, "") AS "Registration Date", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN IF(cr.Letter_Contact_Allowed = 1, "", "A") 
     WHEN br.Business_ID IS NOT NULL THEN IF(br.Letter_Contact_Allowed = 1, "", "A") 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Mail Contact", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN IF(cr.EMail_Contact_Allowed = 1, "", "E") 
     WHEN br.Business_ID IS NOT NULL THEN IF(br.EMail_Contact_Allowed = 1, "", "E") 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "EMail Contact", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN IF(cr.Fax_Contact_Allowed = 1, "", "F") 
     WHEN br.Business_ID IS NOT NULL THEN IF(br.Fax_Contact_Allowed = 1, "", "F") 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Fax Contact", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN IF(cr.Telephone_Contact_Allowed = 1, "", "T") 
     WHEN br.Business_ID IS NOT NULL THEN IF(br.Telephone_Contact_Allowed = 1, "", "T") 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Telephone Contact", 
    COALESCE(CASE WHEN cr.Contact_ID IS NOT NULL THEN 
     CASE WHEN cr.Preferred_Contact_Method = 1 THEN "A" 
      WHEN cr.Preferred_Contact_Method = 2 THEN "E" 
      WHEN cr.Preferred_Contact_Method = 9 THEN "F" 
      WHEN cr.Preferred_Contact_Method = 5 THEN "T" 
     END 
     WHEN br.Business_ID IS NOT NULL THEN 
     CASE WHEN br.Preferred_Contact_Method = 1 THEN "A" 
      WHEN br.Preferred_Contact_Method = 2 THEN "E" 
      WHEN br.Preferred_Contact_Method = 9 THEN "F" 
      WHEN br.Preferred_Contact_Method = 5 THEN "T" 
     END 
     WHEN d.CODE IS NOT NULL THEN "E" 
    END, "") AS "Preferred Support Type", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN cr.Address_1 
     WHEN br.Business_ID IS NOT NULL THEN br.Address_1 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Street Name", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN cr.Postcode 
     WHEN br.Business_ID IS NOT NULL THEN br.Postcode 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Post Code", 
    "GBR" AS Country, 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN cr.Address_2 
     WHEN br.Business_ID IS NOT NULL THEN br.Address_2 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Address 1", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN cr.Address_3 
     WHEN br.Business_ID IS NOT NULL THEN br.Address_3 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Address 2", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN cr.Address_4 
     WHEN br.Business_ID IS NOT NULL THEN br.Address_4 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Address 3", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN cr.Email_Address 
     WHEN br.Business_ID IS NOT NULL THEN br.Email_Address 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Email", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN cr.Tel_num_home 
     WHEN br.Business_ID IS NOT NULL THEN br.Tel_num_primary 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Phone Number 1", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN cr.Tel_num_mobile 
     WHEN br.Business_ID IS NOT NULL THEN br.Tel_num_secondary 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Phone Number 2", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN cr.Tel_num_business 
     WHEN br.Business_ID IS NOT NULL THEN br.Tel_num_mobile 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Phone Number 3", 
    CASE WHEN cr.Contact_ID IS NOT NULL THEN cr.Fax_num 
     WHEN br.Business_ID IS NOT NULL THEN br.Fax_num 
     WHEN d.CODE IS NOT NULL THEN "" 
    END AS "Fax Number", 
    wb.Owner_ID AS "Owner", 
    1 AS "Labour Flag", 
    "WARRANTY" 
FROM 
    I 
    INNER JOIN iba ON I.monetary_transaction_id = iba.monetary_transaction_id 
    INNER JOIN ibi ON ibi.booking_id = iba.booking_id AND ibi.job_group = iba.job_group AND ibi.sequence = iba.sequence 
    INNER JOIN G ON G.Booking_item_id= Ibi.ID 
     AND g.Type_ID = 1 
    INNER JOIN C ON C.ID = G.Claim_Booking_claim_ID 
    INNER JOIN WM ON WM.Warranty_Booking_Claim_ID = C.ID 
    INNER JOIN mwc ON mwc.ID = WM.Manufacturer_Warranty_Claim_ID 
    INNER JOIN ibia ON ibia.booking_item_id = ibi.id 
     AND ibia.sequence = ibi.sequence AND ibia.booking_account_id = iba.id AND ibia.sequence = iba.sequence 
    INNER JOIN wb ON wb.booking_id = ibi.booking_id 
    INNER JOIN a ON a.account_id = iba.account 
    INNER JOIN act ON act.type = a.type 
    LEFT JOIN ibev ON ibev.booking_item_id = ibi.id AND ibi.sequence = ibev.sequence 
    INNER JOIN vm ON wb.vehicle_id = vm.vehicle_id 
    INNER JOIN mwd ON mwd.department_id = I.department_id 
    INNER JOIN mt ON I.monetary_transaction_id = mt.master_monetary_transaction_id 
    INNER JOIN I2 ON mt.id = I2.monetary_transaction_id 
    INNER JOIN acc ON iba.account = acc.account_id 
    LEFT JOIN cr ON wb.owner_id = cr.contact_id 
    LEFT JOIN br ON wb.owner_id = br.business_id 
    LEFT JOIN d ON wb.owner_id = d.code 

    WHERE I.department_id IN (120, 322, 362) 
    AND I.created_date BETWEEN '2011-03-01 00:00:00' AND '2011-03-02 23:59:59' 
    AND ibev.booking_item_id IS NULL AND NOT ibi.booking_item_type_id IN (10,14) AND ibi.warranty_percentage > 0 
    AND wb.booking_id IN (454017, 454019, 454021, 454031) 
+0

說明看起來不錯,沒有臨時性的東西,表掃描(ALL)都很低。你的MySQL服務器是否有足夠的查詢緩存來爲你構建它。也許也提供給我們SQL。 – Pentium10 2011-03-17 15:06:02

+0

已添加SQL查詢。 MySQL服務器有大量的緩存,我確保這個查詢是當時唯一運行的。 – anothershrubery 2011-03-17 15:16:17

+0

您可以檢查並查看是否回滾查詢仍然運行緩慢的更改。如果可以,請爲此創建一個解釋,然後在舊+新版本上運行配置文件,並將所有詳細信息與原始更快的查詢一起發回。 – Pentium10 2011-03-17 15:45:13

回答

1

只要您的查詢涉及如此多的表格 - 它通常會帶來設計問題。除此之外,我注意到你有一個LEFT(OUTER)和INNER JOIN的混合。

除非表格之間存在特定的依賴關係,例如,

A LEFT JOIN B on (a..b) INNER JOIN C on (c..b) 

(C必須B之後來臨)

你應該組在一起的所有內儘可能早地,例如JOIN的而不是

A LEFT JOIN B on (a..b) INNER JOIN C on (c..a) 

把它寫成

A INNER JOIN C on (c..a) LEFT JOIN B on (a..b) 

這將有助於優化過程中的內連接第一,這潛在地降低了行計數。按照定義,LEFT JOIN保留前表的所有行,所以優化器通常會在稍後執行後續表。

+1

儘管我不同意設計問題聲明,但這些表都是必需的,我可以看到爲什麼我們應該將'LEFT JOIN's移動到INNER'下面,因此將標記爲答案。但是,如果我將另一個'LEFT JOIN'(ibev)移動到其他'LEFT JOIN'的底部,查詢現在需要14秒... – anothershrubery 2011-03-18 09:33:02

0

到現在爲止,我可以看到優化查詢的末尾:

例如,這可以被改寫

WHERE I.department_id IN (120, 322, 362) 
    AND I.created_date BETWEEN '2011-03-01 00:00:00' AND '2011-03-02 23:59:59' 
    AND ibev.booking_item_id IS NULL AND NOT ibi.booking_item_type_id IN (10,14) AND ibi.warranty_percentage > 0 
    AND wb.booking_id IN (454017, 454019, 454021, 454031) 

 JOIN (SELECT 120 AS d 
      UNION ALL 
      SELECT 322 AS d 
      UNION ALL 
      SELECT 362) d1 
     ON d1.d = i.department_id 
     JOIN (SELECT 454017 AS b 
      UNION ALL 
      SELECT 454019 AS b 
      UNION ALL 
      SELECT 454021 AS b 
      UNION ALL 
      SELECT 454031 AS b) d2 
     ON d2.b = wb.booking_id 
     LEFT JOIN (SELECT 10 AS bt 
        UNION ALL 
        SELECT 14 AS bt) d3 
     ON d3.bt <> ibi.booking_item_type_id 
WHERE i.created_date BETWEEN '2011-03-01 00:00:00' AND '2011-03-02 23:59:59' 
     AND ibev.booking_item_id IS NULL 
     AND ibi.warranty_percentage > 0 

其中我們採用IN選項並放入派生的靜態表中,以便在它們的匹配上--ON子句 - 索引sh可以使用。 MySQL在連接上使用索引,但不在IN子句中使用。

您需要太多以下列添加索引

  • I.department_id
  • wb.booking_id
  • ibi.booking_item_type_id
1

OK,我rejigged的JOIN的秩序「 s並移動:

INNER JOIN mwd ON mwd.department_id = I.department_id 

成爲第一個JOIN。現在查詢需要8秒!所以這就是固定的。但任何人都可以解釋爲什麼會發生?

+0

我把這個問題的答案(?)作爲答案。 – RichardTheKiwi 2011-03-18 09:04:43