2016-08-02 82 views
0

我試圖讓它們我們的網站中使用的所有圖像的出口(到表)。我的工作代碼在小數據集上表現良好,但仍然尚未從我們的超過4,000張圖像的數據集返回結果。我有類似的代碼下面我select語句:MySQL的多次join曹景偉至尊放緩

SELECT a.id, a.image_name, a.last_modified, c1.val 
    FROM a 
    /*file name could be used in table 'r' in the image1, image2, or image3 fields*/ 
    LEFT JOIN r ON a.image_name = r.image1 
     OR a.image_name = r.image2 
     OR a.image_name = r.image3 
    /*file name could be used anywhere within c.val field*/ 
    LEFT JOIN c c1 ON c1.val LIKE CONCAT('%', a.image_name,'%') 
    /*get the page_id where the image name is found in c*/ 
    LEFT JOIN p p1 ON p1.page_id = c1.page_id 
    WHERE a.type = 'Image' /*only images on this query*/ 
    AND r.image1 IS NULL /*no references in r.image1*/ 
    AND r.image2 IS NULL /*no references in r.image2*/ 
    AND r.image3 IS NULL /*no references in r.image3*/ 
    AND c1.val IS NULL /*no references in c.val OR...*/ 
    /*in the page where it was found, see if the page is a deleted page*/ 
    OR a.id NOT IN (SELECT a.id FROM a 
     LEFT JOIN c c2 ON c2.val LIKE CONCAT('%', a.image_name, '%') 
     LEFT JOIN p p2 ON p2.page_id = c2.page_id 
     WHERE p2.deleted IS NULL) /*deleted IS NULL means the page is not deleted*/ 
    ORDER BY a.last_modified DESC 

實際上有兩種情況時,圖像會在這個出口顯示:

  1. 它沒有發現任何地方
  2. 它的發現一個已被刪除的頁面

第一個是由外部SELECT減去OR a.id NOT IN...部分得到的。第二個是使用內部SELECT獲得的,我確保id不包含在未刪除的頁面中。

我試過將OR a.id NOT IN...更改爲OR p1.deleted IS NOT NULL以取出內部SELECT的開銷,但是這給了我在刪除的頁面中找到的所有圖像,而不一定是僅在刪除的頁面中找到的圖像。

我已經試過索引p.deleted,r.image1,r.image2和r.image3與效率沒有增加字段。我也試着讓BLOB字段,c.val,FULLTEXT索引,這也沒有幫助。

a.id,a.image_name,c.page_id和p.page_id已經索引。

再次,這是工作的代碼,但我只是想提高性能,所以我們可以把代碼投入生產使用我們全面的數據集。感謝您提前回復。

+1

無論你做什麼,連接到所有地方的字符串,特別是帶有通配符的字符串都會導致性能下降;但如果通過將此分解爲6個單獨的查詢(「OR」傾向於使MySQL忽略索引)來消除「OR」,則可能會有一些溫和的改進。 – Uueerdo

+0

我該如何連接6個單獨的查詢?我使用ADODB和$ result = $ db-> execute($ sql)@Uererdo – GrayFoxStudios

+1

你應該可以使用'UNION'。 – Uueerdo

回答

1

對不起雁追我的意見開始,我應該看着查詢接近;但這可能會有所幫助......

SELECT a.id, a.image_name, a.last_modified, c1.val 
FROM a 
LEFT JOIN (
    /*file name could be used in table 'r' in the image1, image2, or image3 fields*/ 
    SELECT 1 AS matched, image1 AS image FROM r 
    UNION SELECT 1, image2 FROM r 
    UNION SELECT 1, image3 FROM r 
) AS r2 ON a.image_name = r2.image 
/*file name could be used anywhere within c.val field*/ 
LEFT JOIN c c1 ON c1.val LIKE CONCAT('%', a.image_name,'%') 
/*get the page_id where the image name is found in c*/ 
LEFT JOIN p p1 ON p1.page_id = c1.page_id 
WHERE a.type = 'Image' /*only images on this query*/ 
AND r2.matched IS NULL /*no references in r.image1, r.image2, or r.image3*/ 
AND (
    c1.val IS NULL /*no references in c.val OR...*/ 
    /*in the page where it was found, see if the page is a deleted page*/ 
    OR a.id NOT IN (
     SELECT a.id 
     FROM a 
      LEFT JOIN c c2 ON c2.val LIKE CONCAT('%', a.image_name, '%') 
      LEFT JOIN p p2 ON p2.page_id = c2.page_id 
     WHERE p2.deleted IS NULL 
    ) /*deleted IS NULL means the page is not deleted*/ 
) 
ORDER BY a.last_modified DESC 
+0

你解決了你可能的問題,OP應該知道這部分,LEFT JOIN c c1 ON c1.val LIKE CONCAT('%',a.image_name,'%')永遠不會很快,它確實表明數據庫設計非常糟糕,應該修復而不是嘗試性能調整由於不良設計選擇而無法調整的內容。 – HLGEM

+0

經過三次測試運行約500個數據集後,您的代碼將性​​能提高了約半秒,從約9.8秒增加到約9.3秒。我很高興我正在取得進展,但我知道它受到我正在使用的CONCAT的限制。我希望我會設計數據庫,但是在我到達這裏之前就已經完成了。 'c.val'被用作我們的內容管理系統中不同可編輯字段的「值」字段。我們使用CKEditor,c.val條目是完整的HTML,將自己寫入屏幕。如果一個圖像被添加到src標記中,我需要知道,因此CONCAT %% @Uueerdo @HLGEM – GrayFoxStudios

+0

我不知道mysql,但WHERE NOT EXISTS通常比SQL IN中的NOT IN更快。值得一試。 Alos可能值得將C中的數據拉出到滿足條件的臨時表中,併爲其提供與image_name部分完全匹配的額外列。 (並且如果mysql允許的話,索引連接字段上的臨時表)因此,當您在主查詢中使用它時(它在該連接處被引用兩次)時,只有已經過濾的值。 – HLGEM