Add STRAIGHT_JOIN to ApiQueryLogEvents and LogPager to avoid planner oddness
[lhc/web/wiklou.git] / includes / api / ApiQueryLogEvents.php
index edf7002..962d956 100644 (file)
@@ -112,7 +112,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
 
                if ( !is_null( $params['tag'] ) ) {
                        $this->addTables( 'change_tag' );
-                       $this->addJoinConds( [ 'change_tag' => [ 'INNER JOIN',
+                       $this->addJoinConds( [ 'change_tag' => [ 'JOIN',
                                [ 'log_id=ct_log_id' ] ] ] );
                        $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
                        try {
@@ -183,6 +183,10 @@ class ApiQueryLogEvents extends ApiQueryBase {
                                $db, 'log_user', User::newFromName( $params['user'], false )
                        );
                        $this->addWhere( $q['conds'] );
+
+                       // T71222: MariaDB's optimizer, at least 10.1.37 and .38, likes to choose a wildly bad plan for
+                       // some reason for this code path. Tell it not to use the wrong index it wants to pick.
+                       $this->addOption( 'IGNORE INDEX', [ 'logging' => [ 'times' ] ] );
                }
 
                $title = $params['title'];
@@ -234,6 +238,14 @@ class ApiQueryLogEvents extends ApiQueryBase {
                        }
                }
 
+               // T220999: MySQL/MariaDB (10.1.37) can sometimes irrationally decide that querying `actor` before
+               // `logging` and filesorting is somehow better than querying $limit+1 rows from `logging`.
+               // Tell it not to reorder the query. But not when `letag` was used, as it seems as likely
+               // to be harmed as helped in that case.
+               if ( $params['tag'] === null ) {
+                       $this->addOption( 'STRAIGHT_JOIN' );
+               }
+
                $count = 0;
                $res = $this->select( __METHOD__ );
                $result = $this->getResult();
@@ -264,7 +276,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
                $user = $this->getUser();
 
                if ( $this->fld_ids ) {
-                       $vals['logid'] = intval( $row->log_id );
+                       $vals['logid'] = (int)$row->log_id;
                }
 
                if ( $this->fld_title || $this->fld_parsedcomment ) {
@@ -281,8 +293,8 @@ class ApiQueryLogEvents extends ApiQueryBase {
                                        ApiQueryBase::addTitleInfo( $vals, $title );
                                }
                                if ( $this->fld_ids ) {
-                                       $vals['pageid'] = intval( $row->page_id );
-                                       $vals['logpage'] = intval( $row->log_page );
+                                       $vals['pageid'] = (int)$row->page_id;
+                                       $vals['logpage'] = (int)$row->log_page;
                                }
                                if ( $this->fld_details ) {
                                        $vals['params'] = LogFormatter::newFromEntry( $logEntry )->formatParametersForApi();
@@ -305,7 +317,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
                                        $vals['user'] = $row->user_name ?? $row->log_user_text;
                                }
                                if ( $this->fld_userid ) {
-                                       $vals['userid'] = intval( $row->log_user );
+                                       $vals['userid'] = (int)$row->log_user;
                                }
 
                                if ( !$row->log_user ) {