使用大量内部联接来改进查询到wp_postmeta,一个键/值表

Jua*_* Jo 10 mysql sql database wordpress entity-attribute-value

我正在使用正在执行以下查询的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
Run Code Online (Sandbox Code Playgroud)

这是解释输出.

+----+-------------+-----------+--------+-----------------------------+----------+---------+------------------------+------+----------------------------------------------+
| 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                                  |
+----+-------------+-----------+--------+-----------------------------+----------+---------+------------------------+------+----------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

Wordpress架构在这里.

O. *_*nes 12

您似乎正在尝试获取每个类型的帖子一行的结果集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 */
Run Code Online (Sandbox Code Playgroud)

在做你想做的事情时理解这种模式是非常重要的.此模式是必需的,因为它postmeta是一种特殊类型的表,称为存储.这里发生了什么?一些东西:

  1. 使用此模式,每个帖子都会有一行,posts表格中有一些列,表格中有一个特定的属性postmeta.
  2. 您正在使用LEFT JOINpostmeta表,因此如果缺少该属性,您仍会获得一行.
  3. 您正在使用postmeta表的别名.在这里postmeta AS color.
  4. 您在连接条件中包含meta_key(此处为'color' = color.meta_key)的选择器ON.
  5. 您在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
Run Code Online (Sandbox Code Playgroud)

我在这个查询上做了一堆缩进,以便更容易看到模式.您可能更喜欢不同的缩进样式.

很难知道为什么在您的问题中出现查询性能问题.这可能是因为您正在进行组合爆炸,INNER JOIN然后对所有操作进行过滤.但无论如何,你展示的查询可能没有返回任何行.

如果仍然遇到性能问题,请尝试postmeta(post_id, meta_key, meta_value)列上创建复合索引.如果你正在创建一个WordPress插件,这可能是插件安装时的一项工作.


Bil*_*win 8

这是一个 Wordpress 数据库,您可能不愿意对架构进行大量更改,因为它可能会破坏应用程序的其他部分或使将来的升级复杂化。

此查询的难度显示了设计的缺点之一。这种设计很灵活,因为它允许在运行时创建新属性,但它使针对此类数据的大量查询比使用传统表更复杂。

Wordpress 的架构没有得到很好的优化。即使在最新的 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));
Run Code Online (Sandbox Code Playgroud)

bk1指数有助于查找完全正确的Meta键值。

bk2指数有助于避免文件排序。

这些索引不能覆盖索引,因为post_titlemeta_valueTEXT列,而且它们太长而无法完全索引。您必须将它们更改为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           |
+----+-------------+--------------+------------+------+---------------+------+---------+----------------------------+------+----------+-----------------------+
Run Code Online (Sandbox Code Playgroud)