【问题标题】:How to improve WordPress insert/update query?如何改进 WordPress 插入/更新查询?
【发布时间】:2020-09-20 23:14:33
【问题描述】:

我正在创建自己的 Wordpress 插件,将配置文件作为帖子导入,并且在脚本工作的同时,我希望改进插入/更新帖子的查询。

此脚本每 5 分钟运行一次,并像这样运行,

1.从本地 users 表中的外部来源导入/更新所有配置文件。这很简单并且可以正常工作

2。在更新之前将所有现有帖子自定义字段 status 设置为离线

$offline = "UPDATE $meta SET meta_value='offline' WHERE meta_key='status'";

3。从表中选择用户所有在线的个人资料

$new_query = "SELECT * FROM users WHERE status='online' ORDER BY visitors DESC";

4。 Foreach 个人资料,如果帖子存在,则更新,否则创建新帖子

$result = $wpdb->get_results($new_query);
foreach ($result as $post){
    $cat = $post->gender.'s';
    $getterm = get_term_by('name',$cat,'user-category');
    $cat_id = $getterm->term_id;
    $custfields = array (
        'name'          => $post->name,
        'age'           => $post->age,
        'subject'       => $post->subject,
        'status'        => $post->status,
        'fans'          => $post->fans,
        'visitors'      => $post->visitors,
    );
    endif;
    $postarr = array (
        'post_title'    => $post->username,
        'post_name'     => $post->username.'-profile',
        'post_content'  => 'something',
        'post_type'     => 'users-profile',
        'post_category' =>  array($cat_id),
        'post_status'   => 'publish',       
        'meta_input'    => $custfields
    );
    $postcheck = get_page_by_title($post->username,OBJECT, 'users-profile');    

    if($postcheck):
            update_post_meta($postcheck->ID ,'subject', $post->subject );
            update_post_meta($postcheck->ID ,'status', $post->status );
            update_post_meta($postcheck->ID ,'visitors', $post->visitors );
    else :
        wp_set_object_terms(wp_insert_post( $postarr,true),$cat_id,'user-category',true);
    endif;
}
SHOW CREATE TABLE wp_users

wp_users    CREATE TABLE `wp_users` (
  `username` varchar(111) COLLATE utf8mb4_unicode_520_ci NOT NULL,
  `name` text COLLATE utf8mb4_unicode_520_ci NOT NULL,
  `age` int(11) NOT NULL,
  `gender` text COLLATE utf8mb4_unicode_520_ci NOT NULL,
  `subject` text COLLATE utf8mb4_unicode_520_ci NOT NULL,
  `languages` text COLLATE utf8mb4_unicode_520_ci NOT NULL,
  `isnew` tinyint(1) NOT NULL,
  `imagebig` text COLLATE utf8mb4_unicode_520_ci NOT NULL,
  `fans` int(11) NOT NULL,
  `visitors` int(11) NOT NULL,
  `timeonline` int(11) NOT NULL,
  `status` text COLLATE utf8mb4_unicode_520_ci NOT NULL,
  `location` text COLLATE utf8mb4_unicode_520_ci NOT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci  

SHOW CREATE TABLE `wp_postmeta`

wp_postmeta 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) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `meta_value` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`meta_id`),
  KEY `post_id` (`post_id`),
  KEY `meta_key` (`meta_key`(191))
) ENGINE=InnoDB AUTO_INCREMENT=405678 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci    

SHOW CREATE TABLE `wp_posts`

wp_posts    CREATE TABLE `wp_posts` (
  `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `post_author` bigint(20) unsigned NOT NULL DEFAULT 0,
  `post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_content` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `post_title` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `post_excerpt` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `post_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'publish',
  `comment_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'open',
  `ping_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'open',
  `post_password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `post_name` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `to_ping` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `pinged` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `post_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `post_content_filtered` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `post_parent` bigint(20) unsigned NOT NULL DEFAULT 0,
  `guid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `menu_order` int(11) NOT NULL DEFAULT 0,
  `post_type` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'post',
  `post_mime_type` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `comment_count` bigint(20) NOT NULL DEFAULT 0,
  PRIMARY KEY (`ID`),
  KEY `post_name` (`post_name`(191)),
  KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),
  KEY `post_parent` (`post_parent`),
  KEY `post_author` (`post_author`)
) ENGINE=InnoDB AUTO_INCREMENT=57991 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 

我想要做的是,在更新/插入之后移动离线开关并将其应用于不在 SELECT 语句中的所有帖子......也许是进行更新/插入的更好方法。

可能是这样的:

从用户表中选择所有在线个人资料,选择与个人资料匹配的帖子(帖子标题=个人资料用户名),如果帖子存在,则更新否则创建,将表中的其余帖子切换为离线。这可能吗?

谢谢

【问题讨论】:

  • 相关表格请提供SHOW CREATE TABLE
  • 更新了问题。感谢您的关注

标签: php mysql wordpress performance wordpress-plugin-creation


【解决方案1】:

前缀索引 (KEY meta_key (meta_key(191))) 是可憎的。是的,由于utf8mb4,这是一个“必要的”组合。但它正在伤害你。这样做

SELECT MAX(CHAR_LENGTH(meta_key)) from wp_postmeta;

如果返回 191 或更少,则将 meta_key 的大小更改为 191 并删除索引中的 (191)。并查看http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta中的其他提示

这些提示可能是您问题的解决方案。

UPDATEing 很多行中的标志似乎是一种笨拙的处理方式。有没有办法在不使用离线/在线标志的情况下简单地折叠新数据? (我想我仍然错过了意图。)如果是一百万行,那么更新可能需要很长时间。

“所有不在 SELECT 中的帖子”——这听起来像是一个“多表 UPDATE”语句。它将涉及LEFT JOIN ON ... WHERE ... IS NULL。你能用重要的列模拟几行吗?向我们展示这些表格中应该包含的内容的“之前”和“之后”。

您也可以将上述操作应用于post_name

ageint(11)

你每年都在增加它吗?

【讨论】:

  • 对于它的价值,James 先生,野外有数以百万计的 WordPress 实例,每个实例的 postmeta 表都以这种方式编入索引。
  • @O.Jones - 是的。在人们开始使用 utf8mb4(在 MySQL 5.5 中引入)之前,不需要 191。而这数百万人中的许多人需要在我的博客中提升性能。我还在 WP Q&A 网站上发布了修复程序,但并没有引起太大的关注。顺便说一句,5.7 消除了对 191 的需要,但用户可能不会删除索引前缀。 :(
  • @RickJames 我希望提高性能,所以我听取了您的建议并从 postmeta 中删除了 meta_id,meta_key 的 max(char_length) 也是 27,所以我将大小更改为 55。
  • @k33n - 我假设您将 PRIMARY KEY 更改为复合键。
  • 我使用在线/离线标志只显示在线的帖子/个人资料,我想不出另一种方法来实现这一点。我同意此更新需要花费大量时间,因为它必须遍历所有现有帖子,这些帖子现在已达到 60k 并且还在增长。这就是为什么我正在研究如何优化它,我正在考虑将 LEFT JOIN 和子查询以准确指定哪些帖子需要更新以及哪些配置文件需要插入,但我仍在努力解决它。更新/插入完成后,我猜离线切换不会对整体性能造成太大影响
猜你喜欢
  • 2021-03-10
  • 2017-04-23
  • 1970-01-01
  • 2015-04-18
  • 1970-01-01
  • 1970-01-01
  • 2016-06-14
  • 1970-01-01
  • 2016-04-14
相关资源
最近更新 更多