MediaWiki  master
runBatchedQuery.php
Go to the documentation of this file.
1 <?php
26 require_once __DIR__ . '/Maintenance.php';
27 
29 
36  public function __construct() {
37  parent::__construct();
38  $this->addDescription(
39  "Run an update query on all rows of a table. " .
40  "Waits for replicas at appropriate intervals." );
41  $this->addOption( 'table', 'The table name', true, true );
42  $this->addOption( 'set', 'The SET clause', true, true );
43  $this->addOption( 'where', 'The WHERE clause', false, true );
44  $this->addOption( 'key', 'A column name, the values of which are unique', true, true );
45  $this->addOption( 'batch-size', 'The batch size (default 1000)', false, true );
46  $this->addOption( 'db', 'The database name, or omit to use the current wiki.', false, true );
47  }
48 
49  public function execute() {
50  $table = $this->getOption( 'table' );
51  $key = $this->getOption( 'key' );
52  $set = $this->getOption( 'set' );
53  $where = $this->getOption( 'where', null );
54  $where = $where === null ? [] : [ $where ];
55  $batchSize = $this->getOption( 'batch-size', 1000 );
56 
57  $dbName = $this->getOption( 'db', null );
58  if ( $dbName === null ) {
59  $dbw = $this->getDB( DB_MASTER );
60  } else {
61  $lbf = MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
62  $lb = $lbf->getMainLB( $dbName );
63  $dbw = $lb->getConnection( DB_MASTER, [], $dbName );
64  }
65 
66  $selectConds = $where;
67  $prevEnd = false;
68 
69  $n = 1;
70  do {
71  $this->output( "Batch $n: " );
72  $n++;
73 
74  // Note that the update conditions do not rely on atomicity of the
75  // SELECT query in order to guarantee that all rows are updated. The
76  // results of the SELECT are merely a partitioning hint. Simultaneous
77  // updates merely result in the wrong number of rows being updated
78  // in a batch.
79 
80  $res = $dbw->select( $table, $key, $selectConds, __METHOD__,
81  [ 'ORDER BY' => $key, 'LIMIT' => $batchSize ] );
82  if ( $res->numRows() ) {
83  $res->seek( $res->numRows() - 1 );
84  $row = $res->fetchObject();
85  $end = $dbw->addQuotes( $row->$key );
86  $selectConds = array_merge( $where, [ "$key > $end" ] );
87  $updateConds = array_merge( $where, [ "$key <= $end" ] );
88  } else {
89  $updateConds = $where;
90  }
91  if ( $prevEnd !== false ) {
92  $updateConds = array_merge( [ "$key > $prevEnd" ], $updateConds );
93  }
94 
95  $query = "UPDATE " . $dbw->tableName( $table ) .
96  " SET " . $set .
97  " WHERE " . $dbw->makeList( $updateConds, IDatabase::LIST_AND );
98 
99  $dbw->query( $query, __METHOD__ );
100 
101  $prevEnd = $end;
102 
103  $affected = $dbw->affectedRows();
104  $this->output( "$affected rows affected\n" );
105  wfWaitForSlaves();
106  } while ( $res->numRows() );
107  }
108 
109  public function getDbType() {
110  return Maintenance::DB_ADMIN;
111  }
112 }
113 
114 $maintClass = RunBatchedQuery::class;
115 require_once RUN_MAINTENANCE_IF_MAIN;
const RUN_MAINTENANCE_IF_MAIN
Definition: Maintenance.php:39
getOption( $name, $default=null)
Get an option, or return the default.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
Definition: Maintenance.php:82
Maintenance script to run a database query in batches and wait for replica DBs.
static getInstance()
Returns the global default instance of the top level service locator.
const DB_MASTER
Definition: defines.php:26
const LIST_AND
Definition: Defines.php:39
wfWaitForSlaves( $ifWritesSince=null, $wiki=false, $cluster=false, $timeout=null)
Waits for the replica DBs to catch up to the master position.
addDescription( $text)
Set the description text.
const DB_ADMIN
Definition: Maintenance.php:89
output( $out, $channel=null)
Throw some output to the user.
$maintClass
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
getDB( $db, $groups=[], $dbDomain=false)
Returns a database to be used by current maintenance script.