可以优化此查询以提高网站的速度吗?

时间:2018-01-04 16:45:24

标签: mysql sql query-optimization

我的查询正在减慢我的Wordpress网站的某个区域。我是sql语句的新手,这个特定的语句是由另一个开发人员创建的。有没有办法优化以下声明?我很茫然!我已经包含了执行计划&桌面设计如下,但很乐意提供任何其他信息。我感谢任何帮助。

SELECT DISTINCT wp_posts.ID FROM wp_posts INNER JOIN (

    SELECT post_id FROM wp_postmeta

            WHERE post_id NOT IN (SELECT post_id FROM wp_postmeta WHERE meta_key = '_wc_restrictions_location')

            AND post_id NOT IN(SELECT DISTINCT tr.object_id FROM wp_termmeta

                INNER JOIN wp_term_taxonomy tt on wp_termmeta.term_id = tt.term_id

                INNER JOIN wp_term_relationships tr on tt.term_taxonomy_id = tr.term_taxonomy_id

                WHERE tt.taxonomy = 'product_cat' AND meta_key='_wc_restrictions_location')

        UNION ALL

    SELECT post_id FROM wp_postmeta

            WHERE (meta_key = '_wc_restrictions_location' AND meta_value = 'public') OR (meta_key = '_wc_restrictions_locations' AND meta_value IN (''))

        UNION ALL

    SELECT tr.object_id FROM wp_termmeta

            INNER JOIN wp_term_taxonomy tt on wp_termmeta.term_id = tt.term_id

            INNER JOIN wp_term_relationships tr on tt.term_taxonomy_id = tr.term_taxonomy_id

            WHERE tt.taxonomy = 'product_cat'

            AND ( (meta_key='_wc_restrictions_location' AND meta_value='public') OR (meta_key = '_wc_restrictions_locations' AND meta_value IN ('')) )

            AND tr.object_id NOT IN (SELECT DISTINCT post_id FROM wp_postmeta WHERE meta_key = '_wc_restrictions_location')

) as rfilter on wp_posts.ID = rfilter.post_id WHERE post_type = 'product' AND ID IN (34913,6926,6928,6929,6931,6932,6933,6934,6935,6936,6937,6938,6942,6943,6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,6955,6921,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6970,6971,6973,6974,6976,6977,6979,6981,6984,6985,6986,6987,6988,6989,6990,6992,6993,6995,6996,6997,6999,7000,7001,7003,7005,7006,7008,7009,7010,7011,7012,7013,7014,7015,7016,7017,7018,7019,7020,7021,7023,7024,7025,7061,7062,7064,7065,7066,7068,7069,7070,7071,7072,7073,7074,7075,7076,7077,7078,7079,7080,7083,7084,7085,7087,7089,7090,7091,7092,7093,7094,7095,7096,7098,7099,7100,7101,7102,7103,7105,7106,7107,7108,7109,7111,7112,7113,7116,7128,7129,7130,7131,7136,7137,7338,7451,7633,7117,7348,7399,7400,7489,7540,7631,24265,24576,34966,35025,35092,35209,35287,35344,35371,35400,35414,35468,35490,35543,35598,35706,35718,35757,35838,35890,35944,36001,36039,36093,36117,36171,36183,36192,38458,39593,39667,39693,39703,39777,39783,39789,42683,44209,44693,45536,45972,46360,46749,48415,48553,48703,48715,48861,49619,49766,51010,51792,52182,53167,53171,53189,53197,53211,53230,53470,53472,53476,53478,53480,53485,53487,53489,53492,53500,53503,53505,53508,53511,53514,53517,53520,53522,53526,53529,53532,53539,53542,53544,53546,53549,53552,53555,53557,53560,53563,53566,53569,53571,53586,53613,53622,53626,53630,53633,53636,53640,53643,53647,53650,53653,53657,53660,53664,53670,53673,53676,53679,53707,53722,53739,53743,53746,53749,53774,53779,53791,53794,53797,53801,53804,53868,53887,53892,53897,53900,53908,53913,53918,53923,54279,54282,54286,54289,54292,54295,54312,54340,54347,54352,54435,54438,54441,54444,54471,54476,54594,54609,54612,54616,54619,54622,7135,35314,53494,53617);

EXPLAIN SELECT结果: enter image description here

描述表结果:

wp_posts    CREATE TABLE `wp_posts` (
  `ID` bigint(20) unsigned NOT NULL,
  `post_author` bigint(20) unsigned NOT NULL DEFAULT '0',
  `post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_content` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `post_title` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `post_excerpt` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `post_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'publish',
  `comment_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'open',
  `ping_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'open',
  `post_password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `post_name` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `to_ping` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `pinged` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `post_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_content_filtered` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `post_parent` bigint(20) unsigned NOT NULL DEFAULT '0',
  `guid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `menu_order` int(11) NOT NULL DEFAULT '0',
  `post_type` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'post',
  `post_mime_type` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `comment_count` bigint(20) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  KEY `post_name` (`post_name`(191)),
  KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),
  KEY `post_parent` (`post_parent`),
  KEY `post_author` (`post_author`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci  

wp_postmeta CREATE TABLE `wp_postmeta` (
  `meta_id` int(11) NOT NULL,
  `post_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  `meta_key` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `meta_value` longtext COLLATE utf8mb4_unicode_ci,
  PRIMARY KEY (`meta_id`),
  KEY `post_id` (`post_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci  

wp_termmeta CREATE TABLE `wp_termmeta` (
  `meta_id` bigint(20) unsigned NOT NULL,
  `term_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  `meta_key` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `meta_value` longtext COLLATE utf8mb4_unicode_ci,
  PRIMARY KEY (`meta_id`),
  KEY `term_id` (`term_id`),
  KEY `meta_key` (`meta_key`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci  

wp_term_taxonomy    CREATE TABLE `wp_term_taxonomy` (
  `term_taxonomy_id` int(11) NOT NULL,
  `term_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  `taxonomy` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `description` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `parent` bigint(20) unsigned NOT NULL DEFAULT '0',
  `count` bigint(20) NOT NULL DEFAULT '0',
  PRIMARY KEY (`term_taxonomy_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci  


wp_term_relationships   CREATE TABLE `wp_term_relationships` (
  `object_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  `term_taxonomy_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  `term_order` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`object_id`,`term_taxonomy_id`),
  KEY `term_taxonomy_id` (`term_taxonomy_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci  

3 个答案:

答案 0 :(得分:2)

我会考虑这两个更改来优化此查询:

  1. 添加适当的索引。
  2. OR条件阻止正确使用索引。因此,我会将条件分为两部分(复制相关的查询部分)并将其与UNION DISTINCT组合。如果您不关心重复项,请将UNION DISTINCT替换为UNION ALL。
  3. 有3个地方你有一个类似于以下的连接ON子句: tt.term_taxonomy_id = tr.term_taxonomy_id 这里的问题是这两列是不同类型的(一个是int(11),另一个是bigint(20))。类型的差异将阻止正确的索引使用。因此,如果可能,我会考虑更改列类型以匹配。
  4. 让我们从添加索引开始:

    ALTER TABLE `wp_postmeta` ADD INDEX `wp_postmeta_index_1` (`meta_key`, `meta_value`, `post_id`);
    ALTER TABLE `wp_postmeta` ADD INDEX `wp_postmeta_index_2` (`meta_key`, `post_id`); 
    ALTER TABLE `wp_posts` ADD INDEX `wp_posts_index_1` (`post_type`, `ID`); 
    ALTER TABLE `wp_term_relationships` ADD INDEX `wp_term_relationships_index_1` (`term_taxonomy_id`, `object_id`); 
    ALTER TABLE `wp_term_taxonomy` ADD INDEX `wp_term_taxonomy_index_1` (`taxonomy`, `term_id`, `term_taxonomy_id`); 
    ALTER TABLE `wp_termmeta` ADD INDEX `wp_termmeta_index_1` (`meta_key`, `meta_value`, `term_id`); 
    ALTER TABLE `wp_termmeta` ADD INDEX `wp_termmeta_index_2` (`meta_key`, `term_id`);
    

    让我们看一下优化的查询:

    SELECT
            DISTINCT wp_posts.ID 
        FROM
            wp_posts 
        INNER JOIN
            (
                SELECT
                    wp_postmeta.post_id 
                FROM
                    wp_postmeta 
                WHERE
                    wp_postmeta.post_id NOT IN (
                        SELECT
                            wp_postmeta.post_id 
                        FROM
                            wp_postmeta 
                        WHERE
                            wp_postmeta.meta_key = '_wc_restrictions_location'
                    ) 
                    AND wp_postmeta.post_id NOT IN (
                        SELECT
                            DISTINCT tr.object_id 
                        FROM
                            wp_termmeta 
                        INNER JOIN
                            wp_term_taxonomy tt 
                                ON wp_termmeta.term_id = tt.term_id 
                        INNER JOIN
                            wp_term_relationships tr 
                                ON tt.term_taxonomy_id = tr.term_taxonomy_id 
                        WHERE
                            tt.taxonomy = 'product_cat' 
                            AND wp_termmeta.meta_key = '_wc_restrictions_location'
                    ) 
                UNION
                ALL SELECT
                    wp_postmeta.post_id 
                FROM
                    wp_postmeta 
                WHERE
                    (
                        wp_postmeta.meta_key = '_wc_restrictions_location' 
                        AND wp_postmeta.meta_value = 'public'
                    ) 
                UNION
                ALL SELECT
                    tr.object_id 
                FROM
                    wp_termmeta 
                INNER JOIN
                    wp_term_taxonomy tt 
                        ON wp_termmeta.term_id = tt.term_id 
                INNER JOIN
                    wp_term_relationships tr 
                        ON tt.term_taxonomy_id = tr.term_taxonomy_id 
                WHERE
                    tt.taxonomy = 'product_cat' 
                    AND (
                        (
                            wp_termmeta.meta_key = '_wc_restrictions_location' 
                            AND wp_termmeta.meta_value = 'public'
                        )
                    ) 
                    AND tr.object_id NOT IN (
                        SELECT
                            DISTINCT wp_postmeta.post_id 
                        FROM
                            wp_postmeta 
                        WHERE
                            wp_postmeta.meta_key = '_wc_restrictions_location'
                    ) 
                UNION
                DISTINCT SELECT
                    wp_postmeta.post_id 
                FROM
                    wp_postmeta 
                WHERE
                    (
                        wp_postmeta.meta_key = '_wc_restrictions_locations' 
                        AND wp_postmeta.meta_value IN (
                            ''
                        )
                    ) 
                UNION
                DISTINCT SELECT
                    tr.object_id 
                FROM
                    wp_termmeta 
                INNER JOIN
                    wp_term_taxonomy tt 
                        ON wp_termmeta.term_id = tt.term_id 
                INNER JOIN
                    wp_term_relationships tr 
                        ON tt.term_taxonomy_id = tr.term_taxonomy_id 
                WHERE
                    tt.taxonomy = 'product_cat' 
                    AND (
                        (
                            wp_termmeta.meta_key = '_wc_restrictions_locations' 
                            AND wp_termmeta.meta_value IN (
                                ''
                            )
                        )
                    ) 
                    AND tr.object_id NOT IN (
                        SELECT
                            DISTINCT wp_postmeta.post_id 
                        FROM
                            wp_postmeta 
                        WHERE
                            wp_postmeta.meta_key = '_wc_restrictions_location'
                    )
                ) AS rfilter 
                    ON wp_posts.ID = rfilter.post_id 
            WHERE
                wp_posts.post_type = 'product' 
                AND wp_posts.ID IN (
                    34913, 6926, 6928, 6929, 6931, 6932, 6933, 6934, 6935, 6936, 6937, 6938, 6942, 6943, 6944, 6945, 6946, 6947, 6948, 6949, 6950, 6951, 6952, 6953, 6954, 6955, 6921, 6956, 6957, 6958, 6959, 6960, 6961, 6962, 6963, 6964, 6965, 6970, 6971, 6973, 6974, 6976, 6977, 6979, 6981, 6984, 6985, 6986, 6987, 6988, 6989, 6990, 6992, 6993, 6995, 6996, 6997, 6999, 7000, 7001, 7003, 7005, 7006, 7008, 7009, 7010, 7011, 7012, 7013, 7014, 7015, 7016, 7017, 7018, 7019, 7020, 7021, 7023, 7024, 7025, 7061, 7062, 7064, 7065, 7066, 7068, 7069, 7070, 7071, 7072, 7073, 7074, 7075, 7076, 7077, 7078, 7079, 7080, 7083, 7084, 7085, 7087, 7089, 7090, 7091, 7092, 7093, 7094, 7095, 7096, 7098, 7099, 7100, 7101, 7102, 7103, 7105, 7106, 7107, 7108, 7109, 7111, 7112, 7113, 7116, 7128, 7129, 7130, 7131, 7136, 7137, 7338, 7451, 7633, 7117, 7348, 7399, 7400, 7489, 7540, 7631, 24265, 24576, 34966, 35025, 35092, 35209, 35287, 35344, 35371, 35400, 35414, 35468, 35490, 35543, 35598, 35706, 35718, 35757, 35838, 35890, 35944, 36001, 36039, 36093, 36117, 36171, 36183, 36192, 38458, 39593, 39667, 39693, 39703, 39777, 39783, 39789, 42683, 44209, 44693, 45536, 45972, 46360, 46749, 48415, 48553, 48703, 48715, 48861, 49619, 49766, 51010, 51792, 52182, 53167, 53171, 53189, 53197, 53211, 53230, 53470, 53472, 53476, 53478, 53480, 53485, 53487, 53489, 53492, 53500, 53503, 53505, 53508, 53511, 53514, 53517, 53520, 53522, 53526, 53529, 53532, 53539, 53542, 53544, 53546, 53549, 53552, 53555, 53557, 53560, 53563, 53566, 53569, 53571, 53586, 53613, 53622, 53626, 53630, 53633, 53636, 53640, 53643, 53647, 53650, 53653, 53657, 53660, 53664, 53670, 53673, 53676, 53679, 53707, 53722, 53739, 53743, 53746, 53749, 53774, 53779, 53791, 53794, 53797, 53801, 53804, 53868, 53887, 53892, 53897, 53900, 53908, 53913, 53918, 53923, 54279, 54282, 54286, 54289, 54292, 54295, 54312, 54340, 54347, 54352, 54435, 54438, 54441, 54444, 54471, 54476, 54594, 54609, 54612, 54616, 54619, 54622, 7135, 35314, 53494, 53617
                )
    

答案 1 :(得分:1)

  • 使用LEFT JOIN ... IS NULL代替NOT IN ( SELECT ... )

  • 关注wp_postmeta的索引tips。 (基于EXPLAIN中的那些巨大数字,这可能会有很大帮助。)

(如果您仍然遇到性能问题,请提供新版本的查询和架构以供进一步批评。)

一些细节......

过去,每个可能的外行都会重新评估IN ( SELECT ... )。这非常低效。较新版本的MySQL / MariaDB可以执行内部SELECT一次,但是然后构造一个索引(不是免费的),或者将其转换为NOT EXISTS ( SELECT ... (slightly modified) ... );这与LEFT JOIN相当具竞争力。

此论坛上充斥着IN (...)和(不常见)NOT IN (...)的示例。 NOT IN构造可能比IN更糟糕。

(对不起,我没有参考,只有多年的经验。)

答案 2 :(得分:1)

如里克所述,应该避免在条款中是否存在,并且存在或不存在。

select col1, col2, col3
from tab1 t1
where exists (select 1 from tab2 where col1 = t1.col1)