【问题标题】:Why is this SELECT statement with nested WHERE subqueries running slowly in MYSQL?为什么这个带有嵌套 WHERE 子查询的 SELECT 语句在 MYSQL 中运行缓慢?
【发布时间】:2014-12-24 04:10:59
【问题描述】:

我编写了一个处理权限的复杂查询,为了使其工作,它在 IF 语句内包含一个嵌套子查询,以仅匹配用户有权访问的那些项目,并匹配条件。

我不确定为什么它运行缓慢,希望能帮助我了解如何调查查询速度。

概述如下:(下面的完整查询)

//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

【问题讨论】:

  • 请发布您正在使用的实际查询,或者至少发布一个比这更完整的替代品。 WHERE 中的子查询通常可以重写为 JOIN,这样可以更好地利用索引,并且不需要对每一行都执行。
  • 我发布的实际查询比较复杂,但总结起来只是为了检索记录匹配权限。

标签: mysql select subquery where


【解决方案1】:

您需要查看很多原因,如果没有更多信息,这将无法诊断。以下是问题列表,按照我建议的处理顺序,让您开始:

首先,您的查询是否支持 SARG? (https://en.wikipedia.org/wiki/Sargable) 显然不是;给定嵌套的子查询。如果你能改变它,它会快得多。 (也许看到第三个问题?)

其次,你能否以不同的方式构造它,从而不需要嵌套的子查询?

第三,您的子查询是否每次都运行相同的东西?您可能希望为此使用临时表,以便在您确实需要嵌套子查询时只对性能造成一次影响。

第四,您的表是否正确索引以优化查询?

最后,您可以尝试与 DBA 合作以实际调查查询性能,看看是否还有其他事情要做。

【讨论】:

  • 我认为第三个匹配我的问题是因为子查询每次都运行相同的东西,这会使主查询变慢。
  • 太棒了 - 如果您可以重写它以使用索引视图或保存所需数据的临时表,它可能会大大提高查询速度。
  • 你能给我一个链接来了解如何使用临时表吗?
  • 我对 MYSQL 不太熟悉,(临时表在不同的 SQL 中大体相似)但这里有一个链接:mysqltutorial.org/mysql-temporary-table,或者这里:linuxplanet.com/linuxplanet/tutorials/6889/1 在这种情况下,您可能会构建跟踪谁有权访问哪些数据集的表。但是,我怀疑您实际上想考虑重写查询以简化逻辑。
猜你喜欢
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
  • 1970-01-01
  • 2011-09-02
  • 2019-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多