mysql - 这个 SQL 语句有更高效的版本吗?

标签 mysql sql wordpress

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

但是,WordPress 不存储元数据添加到帖子的日期,因此我创建了元数据本身 (wpcf-post-likes)、添加日期 (wpcf-post-like-date) 和第三个元数据同时创建,其中包含前两个元数据的 ID,并用感叹号分隔 (wpcf-post-like-date-link)。

然后,我使用以下 SQL 语句来获取当前作者在特定日期后撰写的帖子(示例 ID 包含在下面的 SQL 代码中)的点赞数。它可以工作,但运行时间大约需要 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    

        );

最佳答案

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

您交叉自联接一个临时 View (派生表),这是非常特殊的,但对于 DBMS 来说不应该是一个大问题。它应该注意到您的查询中有两次相同的子查询,并且只处理它一次。 (但是,当交叉连接时,您应该显式地使用CROSS JOIN,以表明这是故意的,并且您不仅仅是忘记了ON子句,就像您使用简单的JOIN所建议的那样。)

那么还有什么需要优化的呢?我已经告诉过你,你应该替换 UNIONUNION ALL如果可能的话,删除 ORDER BYIN条款。此外,您与 LIKE 一起工作和NOT LIKE尽管你不寻找模式。也许您很幸运,DBMS 事先扫描了您的字符串文字,并注意到根本没有可搜索的模式,但也许事实并非如此。不要给 DBMS 做不必要的工作,并使用 =<>相反。

然后您创建了一个从未使用过的meta_type 列,那为什么还要创建它呢?

无论如何,这个查询应该有两个复合索引:一个在 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 包含一个字符串。如果键是“wpcf-post-like-date”,您希望它包含日期时间字符串。但是,它仍然是一个字符串,因此“02-01-1980 09:20:34”比“01-02-2016 09:20:34”大。为了能够比较日期时间,您应该存储“yyyy-mm-dd hh:mi:ss”或转换为日期时间或时间戳。

关于mysql - 这个 SQL 语句有更高效的版本吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35131109/

相关文章:

php - MySQL REPLACE 行,其中字段 a 等于 x,字段 b 等于 y

sql - 列出发布 Ruby on Rails 5 帖子的用户

mysql - 员工详细信息未正确显示

php - 如何使用外部 URL 或链接打开自定义选项卡及其 div?

mysql join, group_concat 和 group by

php - Laravel - 如何从 auth 用户名匹配的另一个表中获取 profile_picture?

PHP/MYSQL : SELECT statement, 多个 WHERE,从数据库填充

sql - 如何修复 ORA-06575 : Package or function is in an invalid state error

php - 在侧边栏外显示小部件

CSS z-index 999 不适用于 Google Chrome 和 Safari 浏览器