Skip to content

SQL performances issues #219

Open
Open
@herewithme

Description

@herewithme

I meet a different performance issues with your great plugin P2P :

My database :

  • 33 000 posts rows
  • 47 000 p2p relations rows
  • 20 000 users rows

My current SQL version : 5.5.27-1~dotdeb.0

SQL queries takes an incredible time (9.0331 sec) with this kind of queries :
When i display a list of custom post type :
http://mywebsite/wp-admin/edit.php?post_type=my_cpt

SELECT wpasc_posts.*, wpasc_p2p.* FROM wpasc_posts INNER JOIN wpasc_p2p WHERE 1=1 AND wpasc_posts.post_type IN ('adherent') AND (wpasc_posts.post_status = 'publish' OR wpasc_posts.post_status = 'future' OR wpasc_posts.post_status = 'draft' OR wpasc_posts.post_status = 'pending' OR wpasc_posts.post_author = 96258 AND wpasc_posts.post_status = 'private') AND (wpasc_p2p.p2p_type = 'member_to_member' AND (
(wpasc_posts.ID = wpasc_p2p.p2p_to AND wpasc_p2p.p2p_from IN (SELECT wpasc_posts.ID FROM wpasc_posts WHERE 1=1 AND wpasc_posts.ID IN (120513,120510,96094,96095,96156,96268,96269,96267,96291,96292,96332,96333,96406,96420,96551,96552,96573,96574,96572,96607) AND wpasc_posts.post_type IN ('adherent') AND (wpasc_posts.post_status = 'publish' OR wpasc_posts.post_status = 'future' OR wpasc_posts.post_status = 'draft' OR wpasc_posts.post_status = 'pending' OR wpasc_posts.post_author = 96258 AND wpasc_posts.post_status = 'private') ORDER BY wpasc_posts.post_date DESC )) OR
(wpasc_posts.ID = wpasc_p2p.p2p_from AND wpasc_p2p.p2p_to IN (SELECT wpasc_posts.ID FROM wpasc_posts WHERE 1=1 AND wpasc_posts.ID IN (120513,120510,96094,96095,96156,96268,96269,96267,96291,96292,96332,96333,96406,96420,96551,96552,96573,96574,96572,96607) AND wpasc_posts.post_type IN ('adherent') AND (wpasc_posts.post_status = 'publish' OR wpasc_posts.post_status = 'future' OR wpasc_posts.post_status = 'draft' OR wpasc_posts.post_status = 'pending' OR wpasc_posts.post_author = 96258 AND wpasc_posts.post_status = 'private') ORDER BY wpasc_posts.post_date DESC ))
)) ORDER BY wpasc_posts.post_date DESC 

Explain results give :

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY wpasc_posts ref PRIMARY,type_status_date,post_author    type_status_date    62  const   18712   Using where; Using temporary; Using filesort
1   PRIMARY wpasc_p2p   ALL p2p_from,p2p_to,p2p_type    NULL    NULL    NULL    47583   Using where; Using join buffer
3   DEPENDENT SUBQUERY  wpasc_posts unique_subquery PRIMARY,type_status_date,post_author    PRIMARY 8   func    1   Using where
2   DEPENDENT SUBQUERY  wpasc_posts unique_subquery PRIMARY,type_status_date,post_author    PRIMARY 8   func    1   Using where

The first problem is that the request is never cached by MySQL (because too large I think)
I made a plugin to simplify the SQL query and finally allow the splitting introduced in WP 3.4. (first get IDS, after get contents with ID

The plugin :

<?php
/*
 Plugin Name: Speedup P2P
 Plugin URI: http://www.beapi.fr
 Description: Change query from P2P plugin, for get ID instead ALL data (*) for posts, make 2 queries instead once !
 Author: BeAPI
 Author URI: http://www.beapi.fr
 Version: 0.1

 ----
 Copyright 2012 Amaury Balmer (amaury@beapi.fr)
 ----
 */

class Speedup_P2P {
    function __construct() {
        add_filter('posts_request', array(&$this, 'posts_request'), 9999999, 2 );
        add_filter('posts_results', array(&$this, 'posts_results'), 1, 2 );
    }

    function posts_request( $request, $query ) {
        global $wpdb;

        $new_request = $request;
        $new_request = str_replace("SELECT SQL_CALC_FOUND_ROWS  $wpdb->posts.*, $wpdb->p2p.* FROM", "SELECT SQL_CALC_FOUND_ROWS $wpdb->posts.ID, $wpdb->p2p.* FROM", $new_request);
        $new_request = str_replace("SELECT   $wpdb->posts.*, $wpdb->p2p.* FROM", "SELECT   $wpdb->posts.ID, $wpdb->p2p.* FROM", $new_request);
        if ( $new_request != $request ) {
            $query->p2p_flag = true;
        }

        return $new_request;
    }

    function posts_results( $posts, $query ) {
        global $wpdb;

        if ( isset($query->p2p_flag) && $query->p2p_flag == true && !empty($posts) ) {
            // Restore flag 
            $query->p2p_flag = false;

            // Get posts IDs for get contents
            $_posts = array();
            foreach( $posts as $post ) {
                $_posts[] = $post->ID;
            }

            // setup posts data
            _prime_post_caches( $_posts, $query->query_vars['update_post_term_cache'], $query->query_vars['update_post_meta_cache'] );
            $_posts = array_map( 'get_post', $_posts );

            // Put ID on key
            foreach( $_posts as $key => $_post ) {
                unset($_posts[$key]);
                $_posts[$_post->ID] = $_post;
            }

            // Merge datas
            $query->posts = array();
            foreach( $posts as $post ) {
                $query->posts[] = (object) array_merge((array) $_posts[$post->ID], (array) $post);
            }

            return $query->posts;
        }

        return $posts;
    }
}
add_action( 'plugins_loaded', create_function('', 'return new Speedup_P2P();') );

The new query :

SELECT wpasc_posts.ID, wpasc_p2p.* FROM wpasc_posts INNER JOIN wpasc_p2p WHERE 1=1 AND wpasc_posts.post_type IN ('adherent') AND (wpasc_posts.post_status = 'publish' OR wpasc_posts.post_status = 'future' OR wpasc_posts.post_status = 'draft' OR wpasc_posts.post_status = 'pending' OR wpasc_posts.post_author = 96258 AND wpasc_posts.post_status = 'private') AND (wpasc_p2p.p2p_type = 'member_to_member' AND (
(wpasc_posts.ID = wpasc_p2p.p2p_to AND wpasc_p2p.p2p_from IN (SELECT wpasc_posts.ID FROM wpasc_posts WHERE 1=1 AND wpasc_posts.ID IN (120513,120510,96094,96095,96156,96268,96269,96267,96291,96292,96332,96333,96406,96420,96551,96552,96573,96574,96572,96607) AND wpasc_posts.post_type IN ('adherent') AND (wpasc_posts.post_status = 'publish' OR wpasc_posts.post_status = 'future' OR wpasc_posts.post_status = 'draft' OR wpasc_posts.post_status = 'pending' OR wpasc_posts.post_author = 96258 AND wpasc_posts.post_status = 'private') ORDER BY wpasc_posts.post_date DESC )) OR
(wpasc_posts.ID = wpasc_p2p.p2p_from AND wpasc_p2p.p2p_to IN (SELECT wpasc_posts.ID FROM wpasc_posts WHERE 1=1 AND wpasc_posts.ID IN (120513,120510,96094,96095,96156,96268,96269,96267,96291,96292,96332,96333,96406,96420,96551,96552,96573,96574,96572,96607) AND wpasc_posts.post_type IN ('adherent') AND (wpasc_posts.post_status = 'publish' OR wpasc_posts.post_status = 'future' OR wpasc_posts.post_status = 'draft' OR wpasc_posts.post_status = 'pending' OR wpasc_posts.post_author = 96258 AND wpasc_posts.post_status = 'private') ORDER BY wpasc_posts.post_date DESC ))
)) ORDER BY wpasc_posts.post_date DESC 

The results of this query are allowed in the cache MySQL queries but are still slow. (1 to 2 seconds)

How can we improve the performance of P2P in a large database? there's there any specific settings to include for mysql?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions