为啥 STRAIGHT_JOIN 会消耗更多 CPU?

Posted

技术标签:

【中文标题】为啥 STRAIGHT_JOIN 会消耗更多 CPU?【英文标题】:Why does STRAIGHT_JOIN consume more CPU?为什么 STRAIGHT_JOIN 会消耗更多 CPU? 【发布时间】:2015-10-27 12:55:11 【问题描述】:

为什么 STRAIGHT_JOIN 比常规连接消耗更多 CPU?你有什么主意吗?

当我在其中一个查询上使用 direct_join 时,它会将查询速度从 12 秒加快到 3 秒。但是它消耗这么多CPU?可能是关于服务器配置或其他什么?

您可能需要检查此评论后的代码 / 主题 ID 正常,正在获取设备... / 在此行之前,有一些关于将 topic_ids 填充到临时表的代码。

这里是查询:

CREATE PROCEDURE `DevicesByTopic`(IN platform TINYINT, IN application TINYINT, IN topicList TEXT, IN page_no MEDIUMINT UNSIGNED)
BEGIN

    DECLARE m_index INT DEFAULT 0;
    DECLARE m_topic VARCHAR(255);
    DECLARE m_topic_id BIGINT UNSIGNED DEFAULT NULL;
    DECLARE m_session_id VARCHAR(40) CHARSET utf8 COLLATE utf8_turkish_ci;

    -- Session Id 
    SET m_session_id = replace(uuid(), '-', '');    

    -- Temp table
    CREATE TEMPORARY TABLE IF NOT EXISTS tmp_topics(
        topic_slug VARCHAR(100) COLLATE utf8_turkish_ci
        ,topic_id BIGINT UNSIGNED
        ,session_id VARCHAR(40) COLLATE utf8_turkish_ci
        ,INDEX idx_tmp_topic_session_id (session_id)
        ,INDEX idx_tmp_topic_id (topic_id)
    ) CHARSET=utf8 COLLATE=utf8_turkish_ci; 

    -- Filling topics in a loop
    loop_topics: LOOP
        SET m_index = m_index + 1;      

        SET m_topic_id = NULL;      
        SET m_topic= SPLIT_STR(topicList,',', m_index);                     

        IF m_topic = '' THEN
            LEAVE loop_topics;      
        END IF;         

        SELECT t.topic_id INTO m_topic_id FROM topic AS t WHERE t.application = application AND (t.slug_hashed = UNHEX(MD5(m_topic)) AND t.slug = m_topic) LIMIT 1;

        -- Fill temp table
        IF m_topic_id IS NOT NULL AND m_topic_id > 0 THEN           
            INSERT INTO tmp_topics 
                (topic_slug, topic_id, session_id)           
            VALUES
                (m_topic, m_topic_id, m_session_id);            
        END IF;

    END LOOP loop_topics;       

    /* Topic Ids are OK, Getting Devices... */

  SELECT 
    dr.device_id, dr.platform, dr.application, dr.unique_device_id, dr.amazon_arn   
  FROM 
    device AS dr
  INNER JOIN (
            SELECT STRAIGHT_JOIN      
            DISTINCT
                d.device_id
            FROM
                device AS d
            INNER JOIN 
                device_user AS du ON du.device_id = d.device_id             
            INNER JOIN 
                topic_device_user AS tdu ON tdu.device_user_id = du.device_user_id
            INNER JOIN
                tmp_topics AS tmp_t ON tmp_t.topic_id = tdu.topic_id
            WHERE
                ((platform IS NULL OR d.platform = platform) AND d.application = application)
                AND d.page_no = page_no     
        AND d.status = 1
                AND du.status = 1               
                AND tmp_t.session_id = m_session_id COLLATE utf8_turkish_ci 
  ) dFiltered ON dFiltered.device_id = dr.device_id
  WHERE
        ((platform IS NULL OR dr.platform = platform) AND dr.application = application)
        AND dr.page_no = page_no        
        AND dr.status = 1;

    -- Delete rows fFill temp table
    DELETE FROM tmp_topics WHERE session_id = m_session_id;

END;

使用 STRAIGHT_JOIN,此查询大约需要 3 秒,但会消耗 90% 的 CPU,但如果我删除关键字“STRAIGHT_JOIN”,则需要 12 秒,但会消耗 12% 的 CPU。

mysql 5.6.19a - innodb

可能是什么原因?

最好的问候。

【问题讨论】:

AND tmp_t.session_id = m_session_id COLLATE utf8_turkish_ci 中的 COLLATE 子句禁止在 session_id 上使用索引;建议您使用一致的排序规则。 “循环”也许可以在没有循环的情况下完成——INSERT INTO tmp_topics SELECT ... WHERE ...。这可能会加快速度。 【参考方案1】:

当您需要覆盖 MySQL 的优化器时,使用 STRAIGHT_JOIN。您是在告诉它忽略其自己的优化执行路径,而是依赖于按照您在查询中写入表的顺序读取表。

99% 的时间您不想使用 straight_join。只需依靠 MySQL 来完成它的工作并为您优化执行路径。毕竟,任何称职的 RDBMS 在优化方面都会相当不错。

您应该使用straight_join 的几次是您已经测试了 MySQL 对给定查询的优化并发现它缺乏。在您使用此查询的情况下,显然您使用 straight_join 进行的手动优化并不比 MySQL 的优化更好。

【讨论】:

straight_join的精彩讨论。

以上是关于为啥 STRAIGHT_JOIN 会消耗更多 CPU?的主要内容,如果未能解决你的问题,请参考以下文章

为啥布尔值比字符消耗更多的内存?

为啥 Numpy 和 Pandas 数组比源数据消耗更多内存? [关闭]

当 cp 没有时,为啥 shutil.copy() 会引发权限异常?

为啥python线程会消耗这么多内存?

为啥 Gaze 会消耗高 CPU?

为啥这段代码会消耗这么多堆?