2014-12-24 80 views
1

我寫了一個處理權限的複雜查詢,爲了使其工作,它在IF語句中包含一個嵌套的子查詢,以僅匹配用戶有權訪問的項目並匹配條件。爲什麼SELECT語句嵌套WHERE子查詢在MYSQL中運行緩慢?

我不確定它爲什麼運行緩慢,並希望得到如何調查查詢速度的幫助。

由於這是什麼樣子的輪廓:(完整的查詢下)

//Main table has many records 

SELECT some field FROM tbl join some table WHERE 

IF (

Subquery (Sub-subquery()) 

) 

完整的查詢:

  -- Get Account By User Assign to 
      SELECT 
      -- SQL_CALC_FOUND_ROWS acc.account_id, 
       acc.`is_delete`, 
       acc.test, CONCAT('<strong>',acc.account_name,'</strong>') AS account_name_alias, 
       CONCAT(u.first_name,' ',u.last_name) created_by_alias, 
       a.account_type_name, 
       i.industry_name, 
       CONCAT(u1.first_name,' ',u1.last_name) 
       modified_by_alias, 
       isp.isp_name, 
       sp.service_plan_name, 
       c.country_name, 
       ci.city_name, 
       d.district_name, 
       co.commune_name 

      FROM crm_accounts AS acc 
      INNER JOIN crm_accounts_assignments asm ON acc.`account_id` = asm.`account_id` 
      LEFT JOIN crm_users u ON acc.created_by = u.user_id 
      LEFT JOIN crm_users u1 ON acc.modified_by = u1.user_id 
      LEFT JOIN crm_account_types a ON acc.account_type = a.account_type_id 
      LEFT JOIN crm_industries i ON acc.industry_id = i.industry_id 
      LEFT JOIN crm_isp_lists isp ON acc.isp_id = isp.isp_id 
      LEFT JOIN crm_service_plans sp ON acc.service_plan_id = sp.service_plan_id 
      LEFT JOIN crm_countries c ON acc.country_id = c.country_id 
      LEFT JOIN crm_cities ci ON acc.city_id = ci.city_id 
      LEFT JOIN crm_districts d ON acc.district_id = d.district_id 
      LEFT JOIN crm_communes co ON acc.commune_id = co.commune_id 
      WHERE acc.is_delete = 0 

      //This my sub query 
      AND 

       IF (
         (
          CASE asm.`assign_type` 
         WHEN 
          EXISTS 
          (
           SELECT 1 FROM crm_user_param_users upu1 
           INNER JOIN crm_users us1 ON upu1.`user1_id` = us1.`user_id` 
           WHERE upu1.`user_id` = 7 AND upu1.`user1_id` = asm.`assign_to_id` 
           AND us1.`role_id` !=2 #User the same Role could not access each other 
           OR EXISTS 
           (
           -- The same Role will be allow if exist at custom share access 
           SELECT 1 FROM `crm_user_param_modules_custom_accesses` mca1 
           WHERE mca1.`module_id` = 1 AND mca1.`user_id` = 7 AND mca1.`role_id` = 2 LIMIT 1 
           ) GROUP BY upu1.`user1_id` LIMIT 1 
          ) 

          OR EXISTS 
          ( 
           -- Only account created by current user 
           SELECT 1 FROM crm_user_param_users upu2 
           INNER JOIN crm_users us2 ON upu2.`user1_id` = us2.`user_id` 
           WHERE upu2.`user_id` = 7 AND acc.`created_by` = upu2.`user1_id` 
           AND us2.`role_id` !=2 #User the same Role could not access each other 
           OR EXISTS 
           (
            -- The same Role will be allow if exist at custom share access 
            SELECT 1 FROM `crm_user_param_modules_custom_accesses` mca2 
            WHERE mca2.`module_id` = 1 AND mca2.`user_id` = 7 AND mca2.`role_id` =2 LIMIT 1 
           ) GROUP BY upu2.`user1_id` LIMIT 1 

          ) 
          OR acc.`created_by` = 7 

         THEN 1 
         ELSE 0 
          END 
        )= 1, 1,0 
       ) = 1 

       OR 

       IF (
         (
          CASE asm.`assign_type` 
         WHEN 
         EXISTS 
          ( 
          SELECT 1 FROM `crm_user_param_groups` upg1 
          INNER JOIN crm_users us1 ON upg1.`user_id` = us1.`user_id` 
          WHERE upg1.`user_id` = 7 AND upg1.`group_id` = asm.`assign_to_id` 
          AND us1.`role_id` !=2 #User the same Role could not access each other 

          -- The same Role will be allow if exist at custom share access -- 
          OR EXISTS 
          (
           SELECT 1 FROM `crm_user_param_modules_custom_accesses` mca1 
           WHERE mca1.`module_id` = 1 AND mca1.`user_id` = 7 AND mca1.`role_id` = 2 LIMIT 1 
          ) LIMIT 1 
         ) 

          -- Only Account created by current user group -- 
          OR EXISTS 
          ( 
          SELECT 1 FROM `crm_user_param_groups` upg2 
          INNER JOIN crm_users us2 ON upg2.`user_id` = us2.`user_id` 
          WHERE upg2.`group_id` = asm.`assign_to_id` AND us2.`user_id` = acc.`created_by` 
          AND us2.`role_id` !=2 #User the same Role could not access each other 
          OR EXISTS 
           (
           -- The same Role will be allow if exist at custom share access -- 
           SELECT 1 FROM `crm_user_param_modules_custom_accesses` mca2 
           WHERE mca2.`module_id` = 1 AND mca2.`user_id` = 7 AND mca2.`role_id` =2 LIMIT 1 
          ) LIMIT 1 

         ) 
         OR acc.`created_by` = 7 

         THEN 2 
         ELSE 0 
          END 
        )= 2, 1,0 
       ) = 1 
+3

請發佈您正在使用的實際查詢,或至少比此更完整的替身。 'WHERE'中的子查詢通常可以重寫爲'JOIN',它可以更好地使用索引,並且不需要爲每行執行。 –

+0

我發佈實際查詢它複雜化,但總結只爲檢索記錄匹配權限。 – Meas

回答

2

有很多的原因,你需要看看,並沒有更多的信息這是不可能診斷的。下面是按照我建議的方法處理的問題列表,以幫助您開始:

首先,您的查詢SARG-able? (https://en.wikipedia.org/wiki/Sargable)它似乎很清楚,它不是;給出嵌套的子查詢。如果你能改變這一點,速度會更快。 (請參閱第三個問題,也許呢?)

其次,你能否以不同的方式構造它,這樣就不需要嵌套的子查詢?

第三,你的子查詢每次都運行相同的東西嗎?如果你真的需要嵌套的子查詢,你可能需要爲此使用臨時表,所以只需要一次性能命中。

第四,您的表格是否正確編入索引以優化查詢?

最後,您可以嘗試使用DBA來實際調查查詢性能,並查看是否有其他事情要做。

+1

與我的問題的第三場比賽,我想因爲子查詢每次運行相同的事情,使主查詢變慢。 – Meas

+0

太好了 - 如果你可以重寫這個來使用索引視圖,或者是一個臨時表來存儲你需要的數據,它可能會大大提高查詢的速度。 –

+0

你能給我一個鏈接,瞭解如何使用臨時表嗎? – Meas