Skip to content

[PLTFRM-1832] Improve query count performance to fix MySQL gone away error#102

Open
andrea-sdl wants to merge 10 commits into
productionfrom
fix/PLTFRM-1832-mysql-gone-away
Open

[PLTFRM-1832] Improve query count performance to fix MySQL gone away error#102
andrea-sdl wants to merge 10 commits into
productionfrom
fix/PLTFRM-1832-mysql-gone-away

Conversation

@andrea-sdl

@andrea-sdl andrea-sdl commented Nov 5, 2025

Copy link
Copy Markdown
Contributor

Description

This PR completely revamps the query logic for counting users.

The goal is to make the query lighter on the database, preventing issues when querying larger sites with many users.

Here are the specific changes in how we're querying

Users without 2FA

Previously we'd rely on the Two_Factor_Core::is_user_using_two_factor( $user_id ) count how many users where not using 2FA which was inefficient.

To make the query lighter, I changed it to use user meta contents. If a user has 2FA enabled, the plugin will set the provider’s user method.

The change is that it no longer uses the plugin to determine which users have 2FA enabled. Instead, it reads the user meta field directly and searches for those who do not have any 2FA set up. In this case, we search for an empty list, false, or null.

This approach is much quicker and should reduce database usage compared to what we had before.

[Not in the PR anymore] Inactive Users

Note: I'm keeping the old description to document my approach, but this was removed in 7ec2a0c and the PR now only focuses on counting the users with 2FA disabled.

For inactive users, the refactoring was more complex.

The main problem with the previous code was the need to check the last login using a user meta value. That meta might be missing if a user never logged in after we activated the integration. We needed to query for both the existence and absence of that meta and account for when Security Boost was activated for users without that meta. Using the default WordPress logic would produce a very long query, especially because we also had to join capabilities to limit results to users with selected roles.

After debugging, we found that querying for both presence and absence of the meta required joining the wp_usermeta table four times. This creates a heavy query, particularly when there is a lot of user meta data.

Before settling on a solution, I considered batching queries throughout the day and storing intermediate results in an option. However, that approach can create issues with DB imports and related operations.

Eventually, I decided to use raw SQL for the inactivity check, assuming the users table does not change frequently. I still didn’t want to rely entirely on SQL, so the query that retrieves user IDs based on capabilities, for example, when tracking inactive admins and editors, is built using the default WordPress APIs. We then extract its SQL and use it to subselect the target users inside the pure SQL query that checks inactivity.

Here's an example of the resulting query on a multisite

SELECT COUNT(DISTINCT u.ID)
			FROM wp_users u
			LEFT JOIN wp_usermeta m_last_seen
				ON u.ID = m_last_seen.user_id
				AND m_last_seen.meta_key = 'wpvip_last_seen'
			WHERE u.user_status = 0 AND u.spam = 0 AND u.deleted = 0
				AND u.user_registered < '2025-08-09 10:49:18'
				AND ((m_last_seen.meta_value IS NOT NULL AND CAST(m_last_seen.meta_value AS UNSIGNED) < 1754736558) OR m_last_seen.meta_value IS NULL)
				AND u.ID IN (SELECT DISTINCT wp_users.ID FROM wp_users WHERE 1=1 AND (wp_users.ID IN (
			SELECT DISTINCT user_id
			FROM wp_usermeta
			WHERE meta_key LIKE 'wp%_capabilities'
			AND (meta_value LIKE '%"manage\\_options";b:1;%' OR meta_value LIKE '%"administrator";b:1%' OR meta_value LIKE '%"edit\\_others\\_posts";b:1;%' OR meta_value LIKE '%"editor";b:1%' OR meta_value LIKE '%"publish\\_posts";b:1;%' OR meta_value LIKE '%"author";b:1%' OR meta_value LIKE '%"edit\\_posts";b:1;%' OR meta_value LIKE '%"contributor";b:1%')
		)))

Pre-review checklist

Please make sure the items below have been covered before requesting a review:

  • This change works and has been tested locally or in Codespaces (or has an appropriate fallback).
  • This change has relevant unit tests (if applicable).
  • This change has relevant documentation additions / updates (if applicable).
  • I've created a changelog description that aligns with the provided examples.

Pre-deploy checklist

  • VIP staff: Ensure any alerts added/updated conform to internal standards (see internal documentation).

Steps to Test

To test this locally, please call

$test_data = apply_filters('vip_site_details_index_security_boost_data', []);

Note: The inactive user module is not part of this PR anymore, ignore the following part.

Alternatively, you can also test the query on a site by sandboxing and adding this file into the /var/www/wp-content/mu-plugins/vip-integrations/vip-security-boost-1.0/modules/inactive-users/ folder and include it into the class-inactive-users.php via

// Load the profiler for performance testing
require_once __DIR__ . '/class-inactive-users-profiler.php'; 

Copilot AI review requested due to automatic review settings November 5, 2025 17:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the Users_Query_Utils::query_users_with_capability_filtering method by extracting query preparation logic into a new reusable helper method get_prepared_user_query_data. Additionally, it optimizes the MFA disabled user count query in the Forced_MFA_Users module by using native meta_query instead of fetching all user IDs and checking them individually.

  • Extracts query preparation logic into get_prepared_user_query_data() for better code reusability
  • Optimizes MFA disabled count by using meta_query to filter users at the database level
  • Adds PHPStan configuration to exclude e2e test node_modules

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
utils/class-users-query-utils.php Refactored by extracting query preparation into get_prepared_user_query_data() method and reorganized query_users_with_capability_filtering() to use the extracted logic
modules/forced-mfa-users/class-forced-mfa-users.php Optimized by adding get_users_without_two_factor_meta_query() method and using it with meta_query to filter users at database level instead of post-query PHP filtering
phpstan.neon Added excludePaths configuration to skip e2e node_modules during static analysis

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread modules/forced-mfa-users/class-forced-mfa-users.php
@andrea-sdl andrea-sdl changed the title [DRAFT][PLTFRM-1832] Improve query count performance to fix MySQL gone away error [PLTFRM-1832] Improve query count performance to fix MySQL gone away error Nov 7, 2025
@andrea-sdl andrea-sdl requested review from a team and Copilot November 7, 2025 11:50
@andrea-sdl

andrea-sdl commented Nov 7, 2025

Copy link
Copy Markdown
Contributor Author

@Automattic/vip-platform-cantina It would be awesome if you could take a moment to check this out, to spot possible issues with this approach, specifically for the SQL changes I did on the inactive users. Happy to add any context if the PR is not clear enough 🙇

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread modules/forced-mfa-users/class-forced-mfa-users.php
Comment thread modules/inactive-users/class-inactive-users.php Outdated
Comment thread modules/inactive-users/class-inactive-users.php
Comment thread modules/inactive-users/class-inactive-users.php
@andrea-sdl andrea-sdl removed the request for review from a team November 7, 2025 17:17
@andrea-sdl

Copy link
Copy Markdown
Contributor Author

@Automattic/vip-platform-cantina After some tests looks like the inactive user fixes are still not enough for when a multisite has so many records in the wp_usermeta table, therefore next week I'll remove that piece and only keep the 2FA counting changes. Your review is now optional, but still appreciated ❤️

@andrea-sdl andrea-sdl changed the title [PLTFRM-1832] Improve query count performance to fix MySQL gone away error [DO NOT MERGE][PLTFRM-1832] Improve query count performance to fix MySQL gone away error Nov 7, 2025
@andrea-sdl andrea-sdl changed the title [DO NOT MERGE][PLTFRM-1832] Improve query count performance to fix MySQL gone away error [PLTFRM-1832] Improve query count performance to fix MySQL gone away error Nov 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants