【问题标题】:MySQL Query Optimization eliminate unnecessary joinsMySQL 查询优化消除不必要的连接
【发布时间】:2011-09-03 11:06:01
【问题描述】:

从概念上讲,我试图为我系统中的每个用户获取 8 个单独的调查分数。我想输出连接到同一行输出的给定用户的所有 8 个分数。这是我实现这一目标的最佳方法:

SELECT cp.CONSUMER_ID,
       bsr1.SCORE AS SET_1_SCORE,
       bsr2.SCORE AS SET_2_SCORE,
       bsr3.SCORE AS SET_3_SCORE,
       bsr4.SCORE AS SET_4_SCORE,
       bsr5.SCORE AS SET_5_SCORE,
       bsr6.SCORE AS SET_6_SCORE,
       bsr7.SCORE AS SET_7_SCORE,
       bsr8.SCORE AS SET_8_SCORE
FROM 
CONSUMER_PROFILE AS cp
LEFT JOIN survey_scores AS bsr1
ON bsr1.SET_ORDER=1 
AND bsr1.CUSTOMER_ID=cp.CONSUMER_ID
LEFT JOIN survey_scores AS bsr2
ON bsr2.SET_ORDER=2
AND bsr2.CUSTOMER_ID=cp.CONSUMER_ID
LEFT JOIN survey_scores AS bsr3
ON bsr3.SET_ORDER=3
AND bsr3.CUSTOMER_ID=cp.CONSUMER_ID
LEFT JOIN survey_scores AS bsr4
ON bsr4.SET_ORDER=4
AND bsr4.CUSTOMER_ID=cp.CONSUMER_ID
LEFT JOIN survey_scores AS bsr5
ON bsr5.SET_ORDER=5
AND bsr5.CUSTOMER_ID=cp.CONSUMER_ID
LEFT JOIN survey_scores AS bsr6
ON bsr6.SET_ORDER=6
AND bsr6.CUSTOMER_ID=cp.CONSUMER_ID
LEFT JOIN survey_scores AS bsr7
ON bsr7.SET_ORDER=7
AND bsr7.CUSTOMER_ID=cp.CONSUMER_ID
LEFT JOIN survey_scores AS bsr8
ON bsr8.SET_ORDER=8
AND bsr8.CUSTOMER_ID=cp.CONSUMER_ID

这会返回正确的输出,但是速度非常慢。你会建议我如何优化它?

【问题讨论】:

  • 请张贴EXPLAIN 输出。

标签: mysql sql optimization query-optimization


【解决方案1】:

您需要的第一件事是关于survey_scores(SET_ORDER, consumer_id, score) 或至少是survey_scores(SET_ORDER, consumer_id) 的索引。然后,即使使用您的查询,它也能很好地工作。

另一种写法是

SELECT cp.CONSUMER_ID,
       MAX(CASE WHEN bsr1.SET_ORDER=1 THEN bsr1.SCORE END) AS SET_1_SCORE,
       MAX(CASE WHEN bsr1.SET_ORDER=2 THEN bsr1.SCORE END) AS SET_2_SCORE,
       MAX(CASE WHEN bsr1.SET_ORDER=3 THEN bsr1.SCORE END) AS SET_3_SCORE,
       MAX(CASE WHEN bsr1.SET_ORDER=4 THEN bsr1.SCORE END) AS SET_4_SCORE,
       MAX(CASE WHEN bsr1.SET_ORDER=5 THEN bsr1.SCORE END) AS SET_5_SCORE,
       MAX(CASE WHEN bsr1.SET_ORDER=6 THEN bsr1.SCORE END) AS SET_6_SCORE,
       MAX(CASE WHEN bsr1.SET_ORDER=7 THEN bsr1.SCORE END) AS SET_7_SCORE,
       MAX(CASE WHEN bsr1.SET_ORDER=8 THEN bsr1.SCORE END) AS SET_8_SCORE
FROM CONSUMER_PROFILE AS cp
LEFT JOIN survey_scores AS bsr1
ON bsr1.SET_ORDER in (1,2,3,4,5,6,7,8)
AND bsr1.CUSTOMER_ID=cp.CONSUMER_ID
GROUP BY cp.CONSUMER_ID

【讨论】:

    【解决方案2】:

    您可以进一步微调:

    SELECT ... FROM consumer_profile as cp    
    LEFT JOIN survey_scores as bsr1  
    ON ((bsr1.Set_Order BETWEEN 1 AND 8)  
      AND (bsr1.Consumer_ID = cp.Consumer_ID))  
    GROUP BY cp.Consumer_ID; 
    

    如果您确定 从不 Set_order 超出范围 1..8 那么您可以删除(bsr1.Set_Order BETWEEN 1 AND 8) AND 部分。

    除此之外,理查德的回答很漂亮。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-04
      • 2020-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      相关资源
      最近更新 更多