我在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
);
答案 0 :(得分:1)
嗯,您正在处理键值表,因此性能问题很自然。
您是跨自己加入临时视图(派生表),这是非常特殊的,但对于DBMS来说不应该是一个大问题。它应该注意到在查询中有两次相同的子查询,并且只处理一次。 (但是,在交叉加入时,您应该明确使用CROSS JOIN
,以便表明这是有目的的,并且您并没有忘记ON
子句作为您对简单{JOIN
的使用1}}建议。)
那还有什么可以优化的?我已经告诉过你,如果可能的话,你应该用UNION
替换UNION ALL
,并删除ORDER BY
条款中的IN
。此外,您使用LIKE
和NOT 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;或转换为日期时间或时间戳。