Wp_postmeta上的简单SQL查询非常慢

时间:2016-12-03 作者:superisc

我有一个wordpress安装,我需要在每篇帖子上查询:

select post_id, meta_key from wp_postmeta where meta_key = \'mykey\' and meta_value = \'somevalue\'
我在那张表上有300万行,查询大约需要6秒钟才能完成。我想应该快得多。如果我显示表的索引,它将返回我:

SHOW INDEX FROM wp_postmeta

Table   Non_unique  Key_name    Seq_in_index    Column_name Collation   Cardinality Sub_part    Packed  Null    Index_type  Comment Index_comment   
wp_postmeta 0   PRIMARY 1   meta_id A   3437260 NULL    NULL        BTREE       
wp_postmeta 1   post_id 1   post_id A   1718630 NULL    NULL        BTREE       
wp_postmeta 1   meta_key    1   meta_key    A   29  191 NULL    YES BTREE   
如果我做出解释,它会给我以下回复:

explain select post_id, meta_key from wp_postmeta where meta_key = \'mykey\' and meta_value = \'somevalue\'


id  select_type table   type    possible_keys   key key_len ref rows    Extra   
1   SIMPLE  wp_postmeta ref meta_key    meta_key    767 const   597392  Using where
我不太擅长mysql,所以我不知道如何检查或解决它。你能告诉我问题出在哪里吗??

谢谢大家。

2 个回复
SO网友:Rick James

wp_postmeta 索引效率低下。已发布的表(参见Wikipedia)为

CREATE TABLE wp_postmeta (
  meta_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  post_id bigint(20) unsigned NOT NULL DEFAULT \'0\',
  meta_key varchar(255) DEFAULT NULL,
  meta_value longtext,
  PRIMARY KEY (meta_id),
  KEY post_id (post_id),
  KEY meta_key (meta_key)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
问题:

AUTO_INCREMENT 不提供任何利益;事实上,它减慢了大多数查询的速度(因为必须在二级索引中查找auto\\u inc id,然后在数据中查找所需的实际id)

  • AUTO_INCREMENT 是额外的混乱-在磁盘和缓存中PRIMARY KEY(post_id, meta_key) -- 群集,处理通常JOIN.
  • BIGINT 有点过头了,但如果不更改其他表,就无法修复
  • VARCHAR(255) 在MySQL 5.6中可能会出现问题utf8mb4; 请参见下面的解决方法NULL?

    CREATE TABLE wp_postmeta (
        post_id BIGINT UNSIGNED NOT NULL,
        meta_key VARCHAR(255) NOT NULL,
        meta_value LONGTEXT NOT NULL,
        PRIMARY KEY(post_id, meta_key),
        INDEX(meta_key)
        ) ENGINE=InnoDB;
    
    典型用法:

    JOIN wp_postmeta AS m  ON p.id = m.post_id
    WHERE m.meta_key = \'...\'
    
    备注:

    复合材料PRIMARY KEY 直接转到所需的行,不要在二级索引中跑题,也不要在多行中搜索

  • INDEX(meta_key) 可能有用,也可能无用,这取决于您有哪些其他查询错误“最大密钥长度为767”,在尝试使用字符集utf8mb4时,MySQL 5.6中可能会发生此错误。执行以下操作之一(每个操作都有缺点)以避免错误:

    升级至5.7.7,3072字节限制——您的云可能不提供此功能

    Potential incompatibilities

    • meta_id 可能没有在任何地方使用。(但移除它是一种风险)meta_id 并通过更改这些索引获得最大的好处:PRIMARY KEY(post_id, meta_key, meta_id), INDEX(meta_id), INDEX(meta_key, post_id). (注:通过meta_id PK结束时,post\\u id+meta\\u密钥可能是非唯一的。)BIGINT 对于较小的数据类型,还需要更改其他表

    utf8mb4

    <移动到5.7不应该是不兼容的VARCHAR(191) 将要求用户了解限制现在是任意的“191”,而不是以前的任意限制“255”

    Comment

    我希望我所倡导的一些东西出现在WordPress路线图上。同时,stackoverflow和dba。stackexchange被“为什么WP运行得这么慢”弄得乱七八糟。我相信这里给出的修复方法将大大减少此类投诉类型的问题。

    请注意,尽管存在兼容性问题,一些用户仍在更改为utf8mb4。然后他们就有麻烦了。我试图解决MySQL的所有问题。

    摘自Rick James mysql博客:source

  • SO网友:Mark Kaplun

    如果您正在寻找“开箱即用”的DB性能,那么post meta表是存储您想要搜索的内容的错误位置。从描述查询的方式来看,最好对该用例使用分类法。

    但是,如果您已经“陷入了兔子洞”,无法重新构建数据库,那么您应该研究缓存解决方案,这可能无助于加快查询速度,但使用良好的缓存,您只会遭受一次延迟。在需要时使用cron生成缓存,不会对用户造成明显影响。

    相关推荐

    将wp_Query替换为wp_User_Query

    我在插件中制作了一些订阅者档案和单曲(个人资料页),其中我还包括了一个“用户单曲”模板,通过template_include. 不过,我正在尝试从插件中删除一些模板,以使其使用主题模板。我用了locate_template( \'single.php\' ) 从活动主题中选择单个模板。我没有使用全局wp_query 在本例中显示我的内容,但页面显示了基于查询默认值的循环(十篇帖子)。我想知道的是,我是否可以完全放弃默认查询,用wp_user_query 我可以将查询到的用户ID输入其中。然后我想筛选the