Skip to content

[Bug]: v1.17.0 WordPress integration: WP_Query with posts_per_page=-1 on every request causes DB overload #3760

Closed

Description

@amashigeseiji

Bug report

Summary

The WordPress integration added in v1.17.0 (PR #3548) executes a WP_Query with posts_per_page => -1 and post_type => 'any' on every request, causing a full table scan of wp_posts each time. On production sites with large post counts, this resulted in DB unavailability.

Environment

  • dd-trace-php version: 1.17.0
  • PHP: 8.2
  • WordPress: 6.7
  • Infrastructure: AWS ECS (multiple tasks running concurrently)

Steps to Reproduce

  1. Install dd-trace-php v1.17.0 on a WordPress site with a large number of posts
  2. Send multiple concurrent requests to the site
  3. Observe heavy DB load / unresponsive MySQL

Root Cause

In WordPressIntegration.php, the following code was added to the WP::main post-hook:

\DDTrace\hook_method('WP', 'main', null, function ($This, $scope, $args) {
    if (class_exists('WP_Query') && !\DDTrace\are_endpoints_collected()) {
        $args = array('post_type' => 'any', 'posts_per_page' => -1);
        $query = new \WP_Query($args);
        foreach ($query->posts as $post) {
            $path = property_exists($post, 'guid') ? $post->guid : '';
            $parsed = parse_url($path);
            if (isset($parsed['path'])) {
                $path = $parsed['path'];
            }
            if (isset($parsed['query'])) {
                $path .= '?' . $parsed['query'];
            }
            $method = 'GET';
            $resourceName = $method . ' ' . $path;
            \DDTrace\add_endpoint($path, 'http.request', $resourceName, $method);
        }
    }
});

This issues the following SQL on every request until are_endpoints_collected() returns true:

SELECT wp_posts.*
FROM wp_posts
WHERE 1 = 1
  AND (
    (wp_posts.post_type = 'attachment' AND (wp_posts.post_status = 'publish' OR ...))
    OR (wp_posts.post_type = 'page'    AND (wp_posts.post_status = 'publish' OR ...))
    OR (wp_posts.post_type = 'post'    AND (wp_posts.post_status = 'publish' OR ...))
    ...
  )
ORDER BY wp_posts.post_date DESC

Why this is dangerous

  1. posts_per_page => -1 causes an unlimited full scan of wp_posts with no LIMIT clause
  2. are_endpoints_collected() is process-local — it does not persist across PHP-FPM workers or container restarts. On ECS, every new task (e.g. after a deployment or scale-out event) re-runs this query on every request until the flag becomes true
  3. Concurrent tasks multiply the load — with many ECS tasks starting simultaneously, all of them issue this query concurrently, accumulating connections and overwhelming RDS

In our case (tens of thousands of posts, ~10 ECS tasks restarting after a deployment), this caused MySQL to become unresponsive and the site to go down.

Additional note on plugin interaction

Active plugins that hook into WP_Query filters (e.g. ACF adds post_status = 'acf-disabled' via posts_where) can further expand the generated SQL in unexpected ways, making the query even heavier.

Impact

  • Production DB outage triggered by a rolling deployment
  • Forced downgrade to v1.16.0 as mitigation

Expected Behavior

Endpoint collection for APM should not issue an unbounded full-table-scan query on every request.

Workaround

Downgrade to v1.16.0, which does not contain this code. Alternatively, set DD_TRACE_WORDPRESS_ENABLED=false, though this disables all WordPress-specific APM spans.

PHP version

8.2.28

Tracer or profiler version

1.17.0

Installed extensions

[PHP Modules]
bcmath
Core
ctype
curl
date
ddappsec
ddtrace
dom
exif
fileinfo
filter
gd
hash
iconv
imagick
intl
json
libxml
mbstring
mysqli
mysqlnd
openssl
pcre
PDO
pdo_sqlite
Phar
posix
random
readline
Reflection
session
SimpleXML
sodium
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
Zend OPcache
zip
zlib

[Zend Modules]
Zend OPcache
ddappsec
ddtrace

Output of phpinfo()

phpinfo

Image

Upgrading from

1.16.0

Activity

  1. bwoebi commented on Apr 1, 2026

    @bwoebi
    Collaborator

    Hey @amashigeseiji,

    we're going to release a 1.17.1 soon, which will remove the endpoint collection from wordpress in this form.
    Doing a full table scan on a potentially large table is definitely bad, and also too high of a cardinality for us anyway.

    We did not think about the fact that there could be a very lot of pages. But that's obviously possible and we're sorry for this!

  2. bwoebi commented on Apr 3, 2026

    @bwoebi
    Collaborator

    We've released 1.17.1, which disables the functionality for Wordpress. We'll look at better solutions in the future - sorry for the outage you did experience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    🐛 bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions