WordPress.org

Make WordPress Core

Opened 3 years ago

Closed 3 years ago

Last modified 2 years ago

#18230 closed enhancement (fixed)

Optimize wp_list_pluck

Reported by: Otto42 Owned by: ryan
Milestone: 3.3 Priority: normal
Severity: normal Version:
Component: Performance Keywords: has-patch
Focuses: Cc:

Description

wp_list_pluck is a bit slow when dealing with objects, due to the array cast. Since we mostly use objects, this is a problem.

Proof code of a speedup enhancement:

function old_wp_list_pluck( $list, $field ) {
	foreach ( $list as $key => $value ) {
		$value = (array) $value;
		$list[ $key ] = $value[ $field ];
	}

	return $list;
}

function new_wp_list_pluck( $list, $field ) {
	foreach ( $list as $key => $value ) {
		if (is_object($value)) $list[$key] = $value->$field;
		else $list[$key] = $value[ $field ];
	}

	return $list;
}

// tested on a site with about 40 tags in the DB
$terms = get_terms('post_tag');

// run both old an new code 10000 times and measure the differences

$start = microtime(true);
for ($i = 1; $i <= 10000; $i++) {
	old_wp_list_pluck($terms,'name');
}	
$end = microtime(true);
var_dump($end - $start);

$start = microtime(true);
for ($i = 1; $i <= 10000; $i++) {
	new_wp_list_pluck($terms,'name');
}
$end = microtime(true);
var_dump($end - $start);

Result:

float(0.85771203041077)
float(0.36069202423096)

New version is slightly more than twice as fast.

Patch forthcoming.

Attachments (1)

18230.diff (499 bytes) - added by Otto42 3 years ago.
optimize wp_list_pluck a little bit

Download all attachments as: .zip

Change History (11)

Otto423 years ago

optimize wp_list_pluck a little bit

comment:1 Otto423 years ago

  • Keywords has-patch added

comment:2 nacin3 years ago

  • Milestone changed from Awaiting Review to 3.3

comment:3 xknown3 years ago

Using isset instead of is_object is a little bit faster apparently.

function new1_wp_list_pluck( $list, $field ) {
	foreach ( $list as $key => $value ) {
		if ( isset( $value->$field ) ) $list[$key] = $value->$field;
		else $list[$key] = $value[ $field ];
	}

	return $list;
}

A simple test with 27 terms.

float(0.71514010429382) // old_wp_list_pluck
float(0.33222508430481) // new_wp_list_pluck
float(0.26003003120422) // new1_wp_list_pluck
Last edited 3 years ago by xknown (previous) (diff)

comment:4 Otto423 years ago

Unfortunately, isset() returns false if $value->$field exists but is set to the null value. So it won't fit with all cases. Using is_object is safer.

comment:5 nacin3 years ago

A note, property_exists() (the equivalent for array_key_exists) doesn't verify magic __get() properties, so I would stick to is_object().

Perhaps we could cache is_object() (pull it outside the loop, etc.) and assume wp_list_pluck() will be operating on only objects or only arrays at any given time.

comment:6 Otto423 years ago

If you make that assumption that the $list array is full of similar objects or arrays, you do get a big speedup.

function new2_wp_list_pluck( $list, $field ) {
	if ( is_object( $list[0] ) ) {
		foreach ( $list as $key => $value )
			$list[ $key ] = $value->$field;
	} else {
		foreach ( $list as $key => $value )
			$list[ $key ] = $value[ $field ];
	}
	
	return $list;
}

float(1.2270720005035) : OLD 
float(0.61718487739563) : NEW
float(0.35837507247925) : NEW2

comment:7 ryan3 years ago

  • Keywords needs-unit-tests added

comment:9 ryan3 years ago

  • Owner set to ryan
  • Resolution set to fixed
  • Status changed from new to closed

In [18602]:

wp_list_pluck() performance improvement. Props Otto42. fixes #18230

comment:10 SergeyBiryukov2 years ago

  • Keywords needs-unit-tests removed
Note: See TracTickets for help on using tickets.