是否有更高效的SQL语句版本?

时间:2016-02-01 12:55:32

标签: mysql sql wordpress

我在WordPress安装中获得了以下在MySQL中运行的SQL语句。我正在寻找符合特定条件的元数据,并且是在特定日期之后创建的。

但是,WordPress没有存储元数据添加到帖子的日期,所以我自己创建了元数据(wpcf-post-likes),添加日期(wpcf-post-like) -date)和第三段元数据,它同时创建,包含由感叹号分隔的前两个ID(wpcf-post-like-date-link)。

然后我使用以下SQL语句在特定日期之后获得当前作者撰写的帖子(下面的SQL代码中包含的示例ID)的喜欢。它有效,但运行大约需要7到8秒,这远非理想。是否有更高效的同一声明版本?

SELECT `meta_id` FROM `wp_postmeta` 
WHERE   `post_id` IN (
            SELECT `ID` FROM `wp_posts` WHERE post_author = $user_id
        ) AND
        `meta_value` IN (

        SELECT CONCAT(combined_ids_a.`meta_id`, '!', combined_ids_b.`meta_id`) AS `combined_meta_id` FROM (

            SELECT `meta_id`, 'like_id' AS `meta_type` FROM `wp_postmeta` 
            WHERE `meta_key` LIKE 'wpcf-post-likes'
            AND `meta_value` NOT LIKE '1837'
            AND `meta_id` IN 
            (SELECT SUBSTRING_INDEX(`meta_value`, '!', 1) FROM `wp_postmeta` WHERE `meta_key` LIKE 'wpcf-post-like-date-link' ORDER BY `meta_id` DESC)

            UNION

            SELECT  `meta_id`, 'like_date' AS `meta_type`  FROM `wp_postmeta` 
            WHERE `meta_key` LIKE 'wpcf-post-like-date'
            AND `meta_value` > '01-02-2016 09:20:34'
            AND `meta_id` IN 
            (SELECT SUBSTRING_INDEX(`meta_value`, '!', -1) FROM `wp_postmeta` WHERE `meta_key` LIKE 'wpcf-post-like-date-link' ORDER BY `meta_id` DESC)

        ) AS combined_ids_a JOIN 

        (

            SELECT `meta_id`, 'like_id' AS `meta_type` FROM `wp_postmeta` 
            WHERE `meta_key` LIKE 'wpcf-post-likes'
            AND `meta_value` NOT LIKE '1837'
            AND `meta_id` IN 
            (SELECT SUBSTRING_INDEX(`meta_value`, '!', 1) FROM `wp_postmeta` WHERE `meta_key` LIKE 'wpcf-post-like-date-link' ORDER BY `meta_id` DESC)

            UNION

            SELECT  `meta_id`, 'like_date' AS `meta_type`  FROM `wp_postmeta` 
            WHERE `meta_key` LIKE 'wpcf-post-like-date'
            AND `meta_value` > '01-02-2016 09:20:34'
            AND `meta_id` IN 
            (SELECT SUBSTRING_INDEX(`meta_value`, '!', -1) FROM `wp_postmeta` WHERE `meta_key` LIKE 'wpcf-post-like-date-link' ORDER BY `meta_id` DESC)

        ) AS combined_ids_b    

        );

1 个答案:

答案 0 :(得分:1)

嗯,您正在处理键值表,因此性能问题很自然。

您是跨自己加入临时视图(派生表),这是非常特殊的,但对于DBMS来说不应该是一个大问题。它应该注意到在查询中有两次相同的子查询,并且只处理一次。 (但是,在交叉加入时,您应该明确使用CROSS JOIN,以便表明这是有目的的,并且您并没有忘记ON子句作为您对简单{JOIN的使用1}}建议。)

那还有什么可以优化的?我已经告诉过你,如果可能的话,你应该用UNION替换UNION ALL,并删除ORDER BY条款中的IN。此外,您使用LIKENOT LIKE,但您不会寻找模式。也许你很幸运,DBMS预先扫描你的字符串文字,并注意到根本没有搜索模式,但也许它没有。不要为DBMS提供比必要更多的工作,而是使用=<>

然后你创建一个你从未使用的meta_type列,那么为什么要创建它?

Anayway,您应该为此查询提供两个复合索引:一个在wp_postmeta(meta_key,meta_id,meta_value)上,以便快速查找元ID。另一个是关于wp_postmeta(meta_key,meta_value)。顺便说一下:你不能为最外面的查询指定meta_key吗?在没有密钥的情况下查找值看起来很奇怪。

查询变为:

select meta_id 
from wp_postmeta 
where post_id in (select id from wp_posts where post_author = $user_id) 
and meta_value in 
(
  select concat(a.meta_id, '!', b.meta_id)
  from
  (
    select meta_id
    from wp_postmeta 
    where meta_key = 'wpcf-post-likes'
    and meta_value <> '1837'
    and meta_id in (select substring_index(meta_value, '!', 1) from wp_postmeta where meta_key like 'wpcf-post-like-date-link')
    union all
    select  meta_id
    from wp_postmeta 
    where meta_key = 'wpcf-post-like-date'
    and meta_value > '01-02-2016 09:20:34'
    and meta_id in (select substring_index(meta_value, '!', -1) from wp_postmeta where meta_key like 'wpcf-post-like-date-link')
  ) a 
  cross join 
  (
    select meta_id
    from wp_postmeta 
    where meta_key = 'wpcf-post-likes'
    and meta_value <> '1837'
    and meta_id in (select substring_index(meta_value, '!', 1) from wp_postmeta where meta_key like 'wpcf-post-like-date-link')
    union all
    select  meta_id
    from wp_postmeta 
    where meta_key = 'wpcf-post-like-date'
    and meta_value > '01-02-2016 09:20:34'
    and meta_id in (select substring_index(meta_value, '!', -1) from wp_postmeta where meta_key like 'wpcf-post-like-date-link')
  ) b 
);

或使用OR代替UNION ALL

select meta_id 
from wp_postmeta 
where post_id in (select id from wp_posts where post_author = $user_id) 
and meta_value in 
(
  select concat(a.meta_id, '!', b.meta_id)
  from
  (
    select meta_id
    from wp_postmeta 
    where 
    (
      meta_key = 'wpcf-post-likes'
      and meta_value <> '1837'
      and meta_id in (select substring_index(meta_value, '!', 1) from wp_postmeta where meta_key like 'wpcf-post-like-date-link' order by meta_id desc)
    )
    or
    (
      meta_key = 'wpcf-post-like-date'
      and meta_value > '01-02-2016 09:20:34'
      and meta_id in (select substring_index(meta_value, '!', -1) from wp_postmeta where meta_key like 'wpcf-post-like-date-link' order by meta_id desc)
    )
  ) a 
  cross join 
  (
    select meta_id
    from wp_postmeta 
    where 
    (
      meta_key = 'wpcf-post-likes'
      and meta_value <> '1837'
      and meta_id in (select substring_index(meta_value, '!', 1) from wp_postmeta where meta_key like 'wpcf-post-like-date-link' order by meta_id desc)
    )
    or
    (
      meta_key = 'wpcf-post-like-date'
      and meta_value > '01-02-2016 09:20:34'
      and meta_id in (select substring_index(meta_value, '!', -1) from wp_postmeta where meta_key like 'wpcf-post-like-date-link' order by meta_id desc)
    )
  ) b 
);

还有一件事:meta_value包含一个字符串。如果密钥是&#39; wpcf-post-like-date&#39;,您希望它包含日期时间字符串。但是,它仍然是一个字符串,所以&#39; 02-01-1980 09:20:34&#39;大于&#39; 01-02-2016 09:20:34&#39;例如。为了能够比较日期时间,您应该存储&#39; yyyy-mm-dd hh:mi:ss&#39;或转换为日期时间或时间戳。