答案是eager loading 或cache 或者两者兼而有之。
快速加载看看这个伪代码:
$ids = get_ids_from_a_db_table();
foreach ( $ids as $id ) {
$row = get_row_from_foreign_table_using( $id );
echo "Row title for the ID: $id is $row->title";
}
如果
$ids
是
n
比这个简单的代码运行
n+1
查询,首先加载id,然后为每个id加载一个id。
你的代码更糟糕,它对每个id运行2个查询,一个用于获取附件帖子对象,一个用于获取附件url(WordPress,不是你,真的吗)
所以您运行2n+1个查询。。。
渴望加载(指db查询)是通过仅在中查询来解决n+1(或2n+1)查询问题的方法one db请求您需要的所有数据(通常使用适当的JOIN
+ WHERE
)
$data = get_data_from_joined_db_tables();
foreach ( $data as $row ) {
echo "Row title for the ID: $row->id is $row->title";
}
这在WordPress中是如何实现的?你需要两件事:
添加适当的join和where子句以合并post meta表过滤返回的字段WP_Query
要包含元表字段,可以使用查询过滤器来完成这两个操作,这里是一个扩展类WP_Query
这样做:
class Thumb_Query extends WP_Query {
protected static $args = array( \'nopaging\' => TRUE );
public function __construct( $args = \'\' ) {
if ( empty( $args ) ) $args = self::$args; // defaults
parent::__construct( $args );
}
public function get_posts() {
add_filter(\'posts_clauses\', array( __CLASS__, \'thumb_filters\') );
$results = parent::get_posts();
remove_filter(\'posts_clauses\', array( __CLASS__, \'thumb_filters\') );
return $this->parse_images( $results );
}
public static function thumb_filters( $pieces ) {
$meta = $GLOBALS[\'wpdb\']->postmeta;
$posts = $GLOBALS[\'wpdb\']->posts;
$pieces[\'fields\'] .= ", thumbs.meta_value as thumb_id";
$pieces[\'fields\'] .= ", imgs.post_title as thumb_title";
$pieces[\'fields\'] .= ", imgdata.meta_value as thumb_file";
$pieces[\'join\'] .= "INNER JOIN {$meta} thumbs ON ({$posts}.ID = thumbs.post_id)";
$pieces[\'join\'] .= " INNER JOIN {$posts} imgs ON (thumbs.meta_value = imgs.ID)";
$pieces[\'join\'] .= " INNER JOIN {$meta} imgdata ON (imgs.ID = imgdata.post_id)";
$where = " AND ( thumbs.meta_key = \'_thumbnail_id\' AND ";
$where .= " CAST( thumbs.meta_value AS SIGNED ) > 0 )";
$where .= " AND ( imgdata.meta_key = \'_wp_attached_file\' )";
$pieces[\'where\'] .= $where;
$pieces[\'groupby\'] = " {$posts}.ID";
return $pieces;
}
protected function parse_images( $rows ) {
$exts = array(\'jpg\', \'jpeg\', \'gif\', \'png\');
foreach ( $rows as $i => $row ) {
$urls = wp_extract_urls( $row->post_content );
$img = FALSE;
while ( ! $img && ! empty($urls) ) {
$url = array_shift($urls);
$ext = strtolower ( pathinfo( $url, PATHINFO_EXTENSION ) );
if ( in_array( $ext, $exts ) ) $img = $url;
}
$rows[$i]->thumb_link = $img ? $img : \'#\';
}
}
}
此类扩展
WP_Query
, 因此,它接受其父级的相同内容,但添加一些过滤器来更改急于加载的thumnail帖子id、thumnail帖子名称和缩略图文件路径。
因此,如果您的查询返回50篇文章,要显示缩略图,请运行101(2n+1)个查询,我的类您只运行1个查询。
此外,在输出结果之前,该类解析所有行,并从帖子内容中提取第一个图像url,并删除添加的过滤器。
如何使用标准WP_Query
参数:
$args = array(
\'post_type\' => \'portfolio\',
\'category_name\' => \'featured\',
\'posts_per_page\' => 50
);
但是使用
Thumb_Query
而不是
WP_Query
$portfolio = new Thumb_Query( $args );
然后循环并输出:
if ( $portfolio->have_posts() ) {
$u = wp_upload_dir();
global $post;
foreach( $portfolio->posts as $post ) {
setup_postdata( $post );
$f = \'<div class="oneCell"><a href="%s" title="%s">\';
$f .= \'<img class="lazy" alt="%s" width="189" src="%s" data-original="%s"/>\';
$f .= \'</a></div>\';
$title = esc_attr( get_the_title() );
printf( $f,
esc_url( $post->thumb_link ),
$title, $title,
esc_url( get_template_directory_uri() . \'/images/grey.png\' ),
esc_url( trailingslashit($u[\'baseurl\']) . $post->thumb_file )
);
}
wp_reset_postdata();
}
在循环中,您可以访问所有标准帖子属性,但每个帖子都有额外的4个属性:
$post->thumb_id
缩略图附件id$post->thumb_title
缩略图附件标题$post->thumb_file
相对于上载文件夹的缩略图文件,类似于\'/2014/04/myfile.jpg\'
$post->thumb_link
发布内容中第一个图像的完整url,如果未找到图像,则为“#”