我正在使用正在执行以下查询的wordpress网站,但我看到这个查询正在进行许多内部联接,并且网站需要很长时间才能加载并且很多,我一直在尝试创建一个生成的查询相同的结果,但尚未成功
我想知道什么是更好的方法来做到这一点
SELECT *
FROM wp_posts
INNER JOIN wp_postmeta color ON wp_posts.ID = color.post_id
INNER JOIN wp_postmeta transmission ON wp_posts.ID = transmission.post_id
INNER JOIN wp_postmeta model ON wp_posts.ID = model.post_id
INNER JOIN wp_postmeta brand ON wp_posts.ID = brand.post_id
AND color.meta_key = 'color'
AND color.meta_value = 'red'
AND transmission.meta_key = 'transmission'
AND transmission.meta_value = 'auto'
AND model.meta_key = 'model'
AND model.meta_value = 'model'
AND brand.meta_key = 'brand'
AND brand.meta_value = 'brand'
AND wp_posts.post_status = 'publish'
AND wp_posts.post_type = 'car'
ORDER BY wp_posts.post_title
这是解释输出。
+----+-------------+-----------+--------+-----------------------------+----------+---------+------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+--------+-----------------------------+----------+---------+------------------------+------+----------------------------------------------+
| 1 | SIMPLE | color | ref | post_id,meta_key | meta_key | 768 | const | 629 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | wp_posts | eq_ref | PRIMARY,type_status_date,ID | PRIMARY | 8 | tmcdb.color.post_id | 1 | Using where |
| 1 | SIMPLE | brand | ref | post_id,meta_key | post_id | 8 | tmcdb.wp_posts.ID | 4 | Using where |
| 1 | SIMPLE | transmission | ref | post_id,meta_key | post_id | 8 | tmcdb.color.post_id | 4 | Using where |
| 1 | SIMPLE | model | ref | post_id,meta_key | post_id | 8 | tmcdb.transmission.post_id | 4 | Using where |
+----+-------------+-----------+--------+-----------------------------+----------+---------+------------------------+------+----------------------------------------------+
答案 0 :(得分:11)
您似乎正在尝试获取每个car
类型帖子一行的结果集。您似乎想在帖子中显示每辆车的各种属性,而这些属性则隐藏在postmeta
中。
专业提示:从不在软件中使用SELECT *
,除非您完全知道为什么要这样做。特别是对于包含大量JOIN
次操作的查询,SELECT *
会返回大量无意义和冗余的列。
有一个查询设计技巧要知道WordPress postmeta
表。如果要获取特定属性,请执行以下操作:
SELECT p.ID, p.post_title,
color.meta_value AS color
FROM wp_posts AS p
LEFT JOIN wp_postmeta AS color ON p.ID = color.post_id AND 'color' = color.meta_key
WHERE p.post_status = 'publish'
AND /* etc etc */
在做你想做的事情时理解这种模式是非常重要的。此模式是必需的,因为postmeta
是一种特殊类型的表,称为key-value或entity-attribute-value存储。这里发生了什么?一些事情:
posts
表中的某些列和postmeta
表中的特定属性。LEFT JOIN
postmeta
表格,因此如果遗失该属性,您仍会获得一行。postmeta
表的别名。这是postmeta AS color
。meta_key
条件中加入'color' = color.meta_key
的选择器(此处为ON
)。SELECT
子句中使用别名,以使用适当的列名称显示postmeta.meta_value
项目。这是color.meta_value AS color
。一旦习惯了这种模式,就可以通过一系列LEFT JOIN
操作将其叠加起来,以获得许多不同的属性,就像这样。
SELECT wp_posts.ID, wp_posts.post_title, wp_posts.whatever,
color.meta_value AS color,
transmission.meta_value AS transmission,
model.meta_value AS model,
brand.meta_value AS brand
FROM wp_posts
LEFT JOIN wp_postmeta AS color
ON wp_posts.ID = color.post_id AND color.meta_key='color'
LEFT JOIN wp_postmeta AS transmission
ON wp_posts.ID = transmission.post_id AND transmission.meta_key='transmission'
LEFT JOIN wp_postmeta AS model
ON wp_posts.ID = model.post_id AND model.meta_key='model'
LEFT JOIN wp_postmeta AS brand
ON wp_posts.ID = brand.post_id AND brand.meta_key='brand'
WHERE wp_posts.post_status = 'publish'
AND wp_posts.post_type = 'car'
ORDER BY wp_posts.post_title
我在这个查询上做了一堆缩进,以便更容易看到模式。您可能更喜欢不同的缩进风格。
很难知道为什么在您的问题中出现查询性能问题。这可能是因为您正在使用所有INNER JOIN
操作进行组合爆炸,然后进行过滤。但无论如何,您展示的查询可能不会返回任何行。
如果您仍遇到性能问题,请尝试在postmeta
列的(post_id, meta_key, meta_value)
上创建复合索引。如果你正在创建一个WordPress插件,这可能是插件安装时的一项工作。
答案 1 :(得分:3)
这是一个Wordpress数据库,您可能不愿意对架构进行大量更改,因为它可能会破坏应用程序的其他部分或将来复杂化升级。
此查询的难度显示了entity-attribute-value设计的缺点之一。该设计非常灵活,因为它允许在运行时创建新属性,但它使得对这些数据的大量查询比使用传统表格更复杂。
The schema for Wordpress has not been optimized well.即使在最新的4.0版本中,也存在一些天真的索引错误。
对于此特定查询,以下两个索引有帮助:
CREATE INDEX `bk1` ON wp_postmeta (`post_id`,`meta_key`,`meta_value`(255));
CREATE INDEX `bk2` ON wp_posts (`post_type`,`post_status`,`post_title`(255));
bk1
索引有助于查找正确的元键和值。
bk2
索引有助于避免文件排序。
这些索引不能覆盖索引,因为post_title
和meta_value
是TEXT
列,而且这些索引太长而无法完全索引。您必须将它们更改为VARCHAR(255)
。但是,如果它依赖于在该表中存储更长的字符串,则存在破坏应用程序的风险。
+----+-------------+--------------+------------+------+---------------+------+---------+----------------------------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------------+------------+------+---------------+------+---------+----------------------------+------+----------+-----------------------+
| 1 | SIMPLE | wp_posts | NULL | ref | bk2 | bk2 | 124 | const,const | 1 | 100.00 | Using index condition |
| 1 | SIMPLE | color | NULL | ref | bk1 | bk1 | 1542 | wp.wp_posts.ID,const,const | 1 | 100.00 | Using index |
| 1 | SIMPLE | transmission | NULL | ref | bk1 | bk1 | 1542 | wp.wp_posts.ID,const,const | 1 | 100.00 | Using index |
| 1 | SIMPLE | model | NULL | ref | bk1 | bk1 | 1542 | wp.wp_posts.ID,const,const | 1 | 100.00 | Using index |
| 1 | SIMPLE | brand | NULL | ref | bk1 | bk1 | 1542 | wp.wp_posts.ID,const,const | 1 | 100.00 | Using index |
+----+-------------+--------------+------------+------+---------------+------+---------+----------------------------+------+----------+-----------------------+
答案 2 :(得分:3)
要解决使用utf8字符集在innodb表上添加10个以上SQL查询的性能问题,请在postmeta上创建一个新索引:
首先备份数据库。将[wp_]postmeta.meta_key
长度减少到191以避免" 指定密钥太长;最大密钥长度为767字节"错误。
ALTER TABLE wp_postmeta MODIFY meta_key VARCHAR(191);
创建索引
CREATE INDEX wpm_ix ON wp_postmeta (post_id, meta_key);
答案 3 :(得分:1)
对于性能尝试:
明确要提取的列。 查看您可能需要或不需要的索引。 限制被拉动的行数。
答案 4 :(得分:1)
这样更好吗?
SELECT
P.*,
C.`meta_value` color,
T.`meta_value` transmission,
M.`meta_value` model,
B.`meta_value` brand
FROM
`wp_posts` P
JOIN
`wp_postmeta` C
ON P.`ID` = C.`post_id` AND C.`meta_key` = 'color'
JOIN
`wp_postmeta` T
ON P.`ID` = T.`post_id` AND T.`meta_key` = 'transmission'
JOIN
`wp_postmeta` M
ON P.`ID` = M.`post_id` AND M.`meta_key` = 'model'
JOIN
`wp_postmeta` B
ON P.`ID` = B.`post_id` AND B.`meta_key` = 'brand'
WHERE
C.`meta_value` = 'red'
AND
T.`meta_value` = 'auto'
AND
M.`meta_value` = 'model'
AND
B.`meta_value` = 'brand'
AND
P.`post_status` = 'publish'
AND
P.`post_type` = 'car'
ORDER BY
P.`post_title`
如果它仍然很慢,可能会尝试添加此索引
CREATE INDEX `IX-wp_postmeta-post_id-meta_key-meta_value`
ON `wp_postmeta` (`post_id`, `meta_key`, `meta_value`);
您也可以尝试将此索引添加到wp_post
CREATE UNIQUE INDEX `IX-wp_post-post_status-post_type-post_title-ID`
ON `wp_post` (`post_stauts`, `post_type`, `post_title`, `ID`);
您可以限制选择列表的次数越多(SELECT
和FROM
之间的位数),就越好。没有必要返回大量您不会使用的数据。如果整个选择列表被索引“覆盖”,您将获得最佳性能。
答案 5 :(得分:1)
假设您实际上可以更改处理结果的代码,我会使它更简单的查询并使用代码来过滤结果。
SELECT [wp_posts fields you care about], wp_postmeta.meta_key, wp_postmeta.meta_value
FROM wp_posts
INNER JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id
WHERE wp_posts.post_status = 'publish' AND wp_posts.post_type = 'car'
AND wp_postmeta.meta_key IN ('color', 'transmission', 'model', 'brand')
ORDER BY wp_posts.post_title, wp_postmeta.meta_key, wp_postmeta.meta_value;
或者,你可以做点像......
SELECT [wp_posts fields desired], COUNT(*) AS matchCount
FROM wp_posts INNER JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id
WHERE wp_posts.post_status = 'publish' AND wp_posts.post_type = 'car'
AND ((meta_key = 'color' AND meta_value = 'red')
OR (meta_key = 'transmission' AND meta_value = 'auto')
OR [etc...]
)
GROUP BY wp_posts.ID
HAVING matchCount = [number of key-value pairs you're checking]
;
答案 6 :(得分:1)
在WordPress中有一个很好的查询工具WP_Query。要搜索post meta值,您可以使用以下代码:
$args = array(
'post_type' => 'post',
'meta_query' => array(
array(
'key' => 'fieldname',
'value' => 'fieldvalue',
'compare' => 'LIKE',
),
),
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
$custom = get_post_custom();
print_r($post);
print_r($custom);
}
} else {
// no posts found
}
wp_reset_postdata();
有关查询API的更多信息,请访问此站点,有很多示例: http://codex.wordpress.org/Class_Reference/WP_Query
答案 7 :(得分:1)