[wp-hackers] Creating Custom Taxonomies on the fly

Mike Schinkel mikeschinkel at newclarity.net
Sun Jan 30 07:02:43 UTC 2011


On Jan 30, 2011, at 1:35 AM, Dion Hulse (dd32) wrote:
> I'll be honest, I'm not a SQL performance nut, and I hate data duplication.
> I've just grabbed a SQL in use on a reasonably -low traffic- site which has about 200 terms in total and a few hundred posts, the result of this is transient cached(which is cleared when tags/cats change) and the site uses super cache as well, So the site has never had any performance issues or scaling problems due to this - Thats not to say it won't in the future of course.
> 
> SELECT DISTINCT t.*
> FROM wp_terms AS t
>  JOIN wp_term_taxonomy AS tt ON ( t.term_id = tt.term_id AND tt.count >0 )
>  LEFT JOIN wp_term_relationships AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
> WHERE tt.taxonomy = 'post_tag'
> AND tr.object_id
> IN (
>  SELECT tr.object_id
>  FROM wp_term_relationships AS tr
>    LEFT JOIN wp_term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
>  WHERE tt.term_id = 3 # This is the Term ID of the category (or any related taxonomy really) that you want to intersect the tags with
> )
> ORDER BY t.name ASC
> 
> I'm sure it's not the best query, it could certainly be optimized (I'm pretty sure it's possible to get rid of that sub select, that'll choke when there are hundeds of posts in a category), but my main reason for digging it up, is the point out that you don't have to load all the posts up, just the ID's of the posts, which is stored in the taxonomy tables anyway.
> 

You are right, it's not very optimized. You really don't need dependent subqueries[1] like that if you can at all help it.  This unravels them:

SELECT DISTINCT 
	wp_terms.*
FROM wp_terms 
	INNER JOIN wp_term_taxonomy ON wp_terms.term_id = wp_term_taxonomy.term_id
	INNER JOIN wp_term_relationships ON wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id
	INNER JOIN wp_term_relationships intersected_term_relationships ON wp_term_relationships.object_id = intersected_term_relationships.object_id
	INNER JOIN wp_term_taxonomy intersected_term_taxonomy ON intersected_term_relationships.term_taxonomy_id = intersected_term_taxonomy.term_taxonomy_id
WHERE 1=1
	AND wp_terms.term_id<>intersected_term_taxonomy.term_id
	AND wp_term_taxonomy.count > 0 
	AND wp_term_taxonomy.taxonomy = 'post_tag'
	AND intersected_term_taxonomy.term_id=3
ORDER BY 
	wp_terms.name ASC

Of course if you are going to use it in PHP for WordPress this would be more useful:

  global $wpdb;
  $sql =<<<SQL
SELECT DISTINCT 
	{$wpdb->terms}.*
FROM {$wpdb->terms}
	INNER JOIN {$wpdb->term_taxonomy} ON {$wpdb->terms}.term_id = {$wpdb->term_taxonomy}.term_id
	INNER JOIN wp_term_{$wpdb->term_taxonomy} ON {$wpdb->term_taxonomy}.term_taxonomy_id = {$wpdb->term_taxonomy}.term_taxonomy_id
	INNER JOIN {$wpdb->term_taxonomy} intersected_term_relationships ON {$wpdb->term_taxonomy}.object_id = intersected_term_relationships.object_id
	INNER JOIN {$wpdb->term_taxonomy} intersected_term_taxonomy ON intersected_term_relationships.term_taxonomy_id = intersected_term_taxonomy.term_taxonomy_id
WHERE 1=1
	AND {$wpdb->terms}.term_id<>intersected_term_taxonomy.term_id
	AND {$wpdb->term_taxonomy}.count > 0 
	AND {$wpdb->term_taxonomy}.taxonomy = 'post_tag'
	AND intersected_term_taxonomy.term_id=%d
ORDER BY 
	{$wpdb->terms}.name ASC
SQL;
  $sql = $wpdb->prepare($sql,3); // 3 is your category ID

Hope this helps.

-Mike
[1] http://www.xaprb.com/blog/2006/04/30/how-to-optimize-subqueries-and-joins-in-mysql/

P.S. Too bad stuff like this isn't available natively in WP_Query.



More information about the wp-hackers mailing list