按优化顺序复杂选择查询

时间:2018-04-16 12:27:57

标签: mysql sql sql-order-by query-performance database-indexes

以下是我的查询引用网址,执行时间为74.086秒,

my complex sql query

和解释声明参考网址

explain statement

但是一旦我删除了此订单条款

 ORDER BY Field( countries.id, 231 ) DESC  

它在6.981秒内执行。

我在本查询中使用的所有列上都使用了索引。

我希望在此查询中需要优化的指导/建议

4 个答案:

答案 0 :(得分:1)

让我们来看看你的查询的一个方面:

SELECT total_fan_count  
  FROM users                                     social_users
  JOIN entities_users                            seu 
    ON seu.user_id = social_users.id
  JOIN entities                                  social_influencers 
    ON social_influencers.id = seu.entity_id
  LEFT 
  JOIN influencers_socialstats                   sss 
    ON sss.influencer_user_id = social_users.id
  LEFT 
  JOIN setup_socialmedia_channels                ssc 
    ON ssc.id = sss.setup_socialmedia_channel_id 
 WHERE social_influencers.id = influencers.id 
   AND ssc.code_name = 'facebook' 
 GROUP 
    BY influencers.id 

一些观察结果:

  1. 这是一个相关的子查询。将其重写为不相关的子查询可能有助于提高性能。

  2. 您有一个GROUP BY子句,但没有聚合函数。在这种情况下,这可能无关紧要,因为您只选择了一列 - 但非常奇怪的是,GROUP BY中的列集与SELECT中的未聚合列的集合不同。

  3. LEFT JOINed表(scc)上有一个WHERE子句。这是矛盾的。将条件移动到ON子句,或切换到INNER JOIN。

  4. 我只检查了这个,很小的一部分,但是如果你的查询中存在这些错误(2和3),那么我不希望它实际上返回一个有效的结果 - 快速或其他。我建议你重新开始,逐个构建查询,观察性能是否会受到影响。

答案 1 :(得分:0)

MySQL正在为每一行执行从属子查询,但您只需要前25行。如果订单不依赖于那些(在这种情况下),您可以通过将订单/限制移动到a来避免这种情况。子查询:

SELECT 
    <dependent subquery1> as campaigns_completed,
    <dependent subquery2> as total_fan_count,
    ...
    t.*
FROM (
    <the rest of your query>
    ORDER BY
        Field( countries.id, 231 ) DESC 
    LIMIT 25 OFFSET 0
) t

答案 2 :(得分:0)

单次通过以获得粉丝计数

所有(?)相关子查询都可以滚动到

CREATE TEMPORARY TABLE tfc
    ( PRIMARY KEY code_name )
    SELECT  ssc.code_name, total_fan_count
        FROM  users AS social_users
        INNER JOIN  entities_users AS seu
               ON seu.user_id = social_users.id
        GROUP BY  seu.entity_id

通过单次传递,这可能比所有相关子查询快得多。

然后使用更简单的查询来获取每列的total_fan_count。

将旋转视为一个单独的步骤

另一种看待这个问题的方法是分两步完成这个过程;第二个是“转动”。

首先执行LIMIT

另一个技巧是从找到你需要的25个ID开始。也就是说,编写 minimal 数量的SQL以获得LIMIT。然后JOIN对其他东西。这可能只允许25次查找等。这可能会绕过您提到的74s vs 6s时间。由于其他原因,它也可能缩短时间。

不要过度标准化

在多个表(城市+州+国家/地区)之间传播“位置”而不是单个位置表会导致SELECT中的大量额外工作,在空间或其他方面几乎没有任何好处。 (城市名称多久更改一次?真相或后果,NM,尽管如此。)

谨防膨胀

JOIN会使正在处理的行数膨胀,只是让您GROUP BY将其缩小回所需的行。我之前的一些评论涉及这种综合症,但也可能涉及其他方面。

答案 3 :(得分:0)

一些建议:

  1. 可以删除一些冗余的LEFT JOIN(例如,setup_influencer_types)。删除它们可以显着提高性能(减少连接数=减少数据库的工作量)。
  2. 在限制之后(而不是之前)在SELECT子句中执行查询可以提供很大帮助,因为每个选择行执行一次这些查询。下面的优化查询包含该修改。
  3. 某些连接可以是INNER JOINed而不是LEFT JOINed(因为对它们进行了过滤,因此没有必要将它们连接起来)。 INNER JOINing的优点是您可以为优化器提供更多选项来选择执行顺序。在大多数情况下,您最终会得到更好的执行计划。
  4. 阅读here,了解如何更好地优化LIMIT&amp; OFFSET子句用于分页。
  5. 总而言之,首先添加优化此查询所需的这些索引:

    ALTER TABLE `campaigns_offered_influencers` ADD INDEX `campaigns_offered_in_idx_status_id` (`campaign_offered_status`,`user_id`);
    ALTER TABLE `entities` ADD INDEX `entities_idx_type_statu_id_id_id_id` (`entity_type`,`row_status`,`id`,`rating_id`,`country_id`,`states_id`);
    ALTER TABLE `entities` ADD INDEX `entities_idx_id` (`id`);
    ALTER TABLE `entities_users` ADD INDEX `entities_users_idx_id_id` (`user_id`,`entity_id`);
    ALTER TABLE `entities_users` ADD INDEX `entities_users_idx_id` (`id`);
    ALTER TABLE `entities_users_roles` ADD INDEX `entities_users_roles_idx_id_id` (`user_id`,`role_id`);
    ALTER TABLE `favourite_influencers` ADD INDEX `favourite_influencer_idx_id_status` (`entity_id`,`row_status`);
    ALTER TABLE `file_attachments` ADD INDEX `file_attachments_idx_id` (`id`);
    ALTER TABLE `influencer_interests` ADD INDEX `influencer_interests_idx_id_id` (`entity_id`,`interest_groups_id`);
    ALTER TABLE `influencers_audience_location` ADD INDEX `influencers_audience_idx_id_id_id_id` (`user_id`,`country_id`,`state_id`,`city_id`);
    ALTER TABLE `influencers_socialstats` ADD INDEX `influencers_socialst_idx_id_id_id` (`influencer_user_id`,`setup_socialmedia_channel_id`,`setup_social_engagement_rate_id`);
    ALTER TABLE `setup_cities` ADD INDEX `setup_cities_idx_id_name` (`id`,`city_name`);
    ALTER TABLE `setup_countries` ADD INDEX `setup_countries_idx_id_name_2_3` (`id`,`country_name`,`iso_code_2`,`iso_code_3`);
    ALTER TABLE `setup_interest_groups` ADD INDEX `setup_interest_group_idx_id_id_name` (`id`,`parent_id`,`interest_name`);
    ALTER TABLE `setup_rating_list` ADD INDEX `setup_rating_list_idx_id_value` (`id`,`display_value`);
    ALTER TABLE `setup_roles` ADD INDEX `setup_roles_idx_id_name_name` (`id`,`code_name`,`role_name`);
    ALTER TABLE `setup_social_engagement_levels` ADD INDEX `setup_social_engagem_idx_id` (`id`);
    ALTER TABLE `setup_socialmedia_channels` ADD INDEX `setup_socialmedia_ch_idx_id` (`id`);
    ALTER TABLE `setup_states` ADD INDEX `setup_states_idx_id_name` (`id`,`state_name`);
    ALTER TABLE `users` ADD INDEX `users_idx_status_verified_id` (`row_status`,`account_verified`,`id`);
    ALTER TABLE `users` ADD INDEX `users_idx_id` (`id`);
    

    然后,尝试运行this optimized query(我使用了pastebin,因为查询对于stackoverflow的限制而言太长了。)

    P.S,我使用EverSQL来优化此查询(针对索引和查询建议)。免责声明:我是EverSQL的联合创始人。