web-dev-qa-db-fra.com

Est-il vrai que $ wpdb-> get_results est plus rapide que WP_Query dans la plupart des cas?

Sur ma page d'accueil, j'ai une section où je dois afficher les cinq derniers articles en vedette, où un article en vedette est simplement un article avec un champ personnalisé is_featured défini sur 1.

J'ai réalisé ce que je veux avec deux types de codes différents:

Utiliser wpdb

<?php    
    $featuredPosts = $wpdb->get_results("
        SELECT ID, post_title FROM $wpdb->posts
        LEFT JOIN $wpdb->postmeta ON($wpdb->posts.ID = $wpdb->postmeta.post_id)
        WHERE $wpdb->postmeta.meta_key = 'is_featured'
        ORDER BY ID DESC LIMIT 5
    ");

    if ($featuredPosts)
    {
        $htmlOutput = '';                   

        foreach ($featuredPosts as $featPost)
            $htmlOutput .= '<br /><a href="'.get_permalink($featPost->ID).'">'.$featPost->post_title.'</a>';
    }

    echo $htmlOutput;
?>


Selon le plug-in "Query Monitor", cette requête prend 0.1 s et génère ce SQL:

SELECT ID, post_title
FROM wp_posts LEFT JOIN wp_postmeta ON(wp_posts.ID = wp_postmeta.post_id)
WHERE wp_postmeta.meta_key = 'is_featured'
ORDER BY ID DESC
LIMIT 5


Utiliser les appels natifs de Wordpress

<?php                                                                       
    $featuredPostsRevised = new WP_Query
    (
        array
        (
            'meta_query' => array
            (
                array
                (
                    'key' => 'is_featured'
                )
            ) 
        ) 
    );  

    while($featuredPostsRevised->have_posts()) : $featuredPostsRevised->the_post();
?>
        <br />
        <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"><?php the_title(); ?></a>
<?php
    endwhile;
?>


Selon le plug-in "Query Monitor", cette requête prend 0.2 s et génère un code SQL plus long:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
INNER JOIN wp_postmeta
ON (wp_posts.ID = wp_postmeta.post_id)
WHERE 1=1
AND wp_posts.post_type = 'post'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private')
AND (wp_postmeta.meta_key = 'is_featured' )
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10

Mes questions sont:

  1. Comment puis-je prepare() ma requête wpdb? J'ai essayé mais je n'y suis pas parvenu à cause du deuxième paramètre.

  2. Après avoir utilisé prepare, ai-je raison de supposer qu'en termes de sécurité et de performances, wpdb est en effet une meilleure solution?

3
WPRookie82

Comment préparer () ma requête wpdb? J'ai essayé mais je n'y suis pas parvenu à cause du deuxième paramètre.

La fonction prepare() est expliquée dans Codex , vous devez avoir une requête avec des espaces réservés et des arguments supplémentaires pour remplacer ces espaces réservés. Si vous n'avez pas d'espaces réservés (donc pas de variables dans la requête), vous pouvez utiliser esc_sql pour éviter les injections SQL, mais cela n'a de sens que lorsque la requête est construite à l'aide de l'entrée utilisateur. La requête dans OP est complètement codée en dur, il n’est donc pas nécessaire de prepare() ni de esc_sql().

Après avoir utilisé prepare, ai-je raison de supposer qu'en termes de sécurité et de performances, wpdb est effectivement une meilleure solution?

Réponse courte: non. WP_Query est juste une approche de niveau supérieur pour les requêtes, il construit une chaîne de requête, puis utilise $wpdb pour exécuter cette requête SQL dans la base de données.

Si vous examinez deux requêtes dans OP, elles sont différentes, par exemple, la requête exécutée à l'aide de $wpdb ne prend pas en compte le statut de publication, la date de publication ou le mot de passe de publication. Par conséquent, si vous avez supprimé des publications, programmées ou privées, en utilisant la première requête ils sont montrés aux utilisateurs. De plus, la requête ne prend pas en compte le classement des résultats et d'autres éléments. Bien sûr, vous pouvez construire une chaîne de requête complexe qui prend en compte tout, puis l'exécuter à l'aide de $wpdb, vous avez deux possibilités:

  1. écrivez une chaîne de requête codée en dur complexe à chaque fois que vous avez besoin d'une boucle: c'est vraiment écrasant et sujet aux erreurs
  2. écrire du code qui traite les requêtes de manière flexible: ce sera très difficile et vous devriez écrire beaucoup de code déjà traité par le noyau dans WP_Query: cela n’a aucun sens.

Il y a un autre facteur important à prendre en compte: WP_Query déclenche pas mal de filtres de filtrage et d'actions, et des milliers de plugins et de thèmes s'en remettent: en exécutant une requête {manuelle} _ $wpdb pour les boucles beaucoup de choses.

Donc, si vous devez interroger publications, utilisez WP_Query: quelques millisecondes ne valent pas des heures et des heures de code et de frustrations. Utilisez $wpdb uniquement lorsque vous devez exécuter des requêtes non gérées par le noyau.

Cela vaut la peine d’ajouter le commentaire @TomJNowell ici:

N'oubliez pas non plus que WP_Query vous permettrait de tirer parti de nombreux caches internes conservés par WordPress, tels que la récupération d'une publication une fois si elle est interrogée une seconde fois, etc. Si vous avez 50 000 publications à interroger simultanément , vous devriez probablement utiliser une file d’attente ou un script CLI pour effectuer votre travail (à moins que vous n’ayez que des dizaines d’utilisateurs et beaucoup d’argent à dépenser sur un serveur)

7
gmazzap