MigrateActors: Improve query for log_search rows
authorBrad Jorsch <bjorsch@wikimedia.org>
Tue, 2 Apr 2019 14:07:56 +0000 (10:07 -0400)
committerBrad Jorsch <bjorsch@wikimedia.org>
Tue, 2 Apr 2019 14:37:24 +0000 (10:37 -0400)
The query in question is, generically,

 SELECT ls_value, ls_log_id, actor_id
  FROM log_search LEFT JOIN actor ON (ls_value = actor_user)
  WHERE ls_field = 'target_author_id'
  ORDER BY ls_value, ls_log_id
  LIMIT 100;

The intention is that it'll pull out 100 rows from log_search using its
primary key, and for each of those 100 rows find the actor_id for the
referenced user_id (using the actor_user index) if an actor ID exists.

The twist comes in the fact that ls_value is a string-type column while
actor_user is an integer-type. MySQL doesn't usually care, but other DBs
do so we have to cast one into the other.

Currently the code is casting actor_user to a string. But that means the
DB can't use the index on actor_user to find the one matching row,
instead it needs to scan the whole table.

The fix is simple enough: instead of casting actor_user to a string,
cast ls_value to an integer. That allows the actor_user index to be used
as expected.

Bug: T215525
Change-Id: I2f7a6ba9fd537336594088a0281a62ea5601cd59

maintenance/includes/MigrateActors.php

index f5b3666..aff6758 100644 (file)
@@ -504,7 +504,7 @@ class MigrateActors extends LoggedUpdateMaintenance {
                                        'ORDER BY' => $primaryKey,
                                        'LIMIT' => $this->mBatchSize,
                                ],
-                               [ 'actor' => [ 'LEFT JOIN', 'ls_value = ' . $dbw->buildStringCast( 'actor_user' ) ] ]
+                               [ 'actor' => [ 'LEFT JOIN', 'actor_user = ' . $dbw->buildIntegerCast( 'ls_value' ) ] ]
                        );
                        if ( !$res->numRows() ) {
                                break;