public function counterMultiple(array $cids, $increment, $default = 0) {
    // TODO: This can be implemented in a batched way (with just one query)
    // and counter() should call counterMultiple(). But again the crippled
    // Drupal's DTBNG is brilliantly doing it's job.
    foreach ($cids as $cid) {
      $this->counter($cid, $increment, $default);
    }
  }

Performance of tag storage when using the database backend could be orders of magnitude better if a good implementation of counterMultiple() was present.

Comments

david_garcia created an issue. See original summary.

david_garcia’s picture

Issue summary: View changes
david_garcia’s picture

Issue summary: View changes

What this basically needs is to expand the Upsert in DBTNG to allow expressions on updates and default values on inserts (while keeping this BC....)

This is the current code:

    $query = $this->connection->update($this->bin);
    $query ->condition('cid', $cid);
    $query ->condition('data_int', NULL, 'IS NOT NULL');
    $query->expression('data_int', "data_int + $increment");

    $result = 0;
    try {
      $result = $query->execute();
    }
    catch (\Exception $e) { }

    if ($result == 0) {

      // Make sure the item does not exist before doing a set...
      $query = $this->connection->select($this->bin);
      $query->addField($this->bin, 'cid');
      $query->condition('cid', $this->normalizeCid($cid));
      $count = count($query->execute()->fetchAll());

      if ($count == 1) {
        throw new \Exception("Counter failed.");
      }

      // Set the default value...
      $this->counterSet($cid, $default);
    }

And this is what a batched version of this code should look like...

    $query = $this->connection->upsert($this->bin);
    $query->key('cid');
    $query->fields(['cid', 'data_int']);

    foreach ($cids as $cid) {
      $query->values([$cid, $default], [$cid, "data_int + $increment"]);
    }

    $query->execute();

The secret sauce is in adding an optional parameter to the Values() method of upsert queries that is able to take a different set of values when doing an update. The problem is that there is no way to distinguish between expressions and values. On inserts there is no point in supporting expressions because there is no previous dataset. Maybe something like this.... but it's too ugly.

  // First arguments are values for INSERT, second are VALUES for UPDATE and third are Expressions for UPDATE.
  $query->values([$cid, $default], [$cid, NULL], [NULL, "data_int + $increment"]);
fabianx’s picture

Tagging as a contrib project blocker.

Need to support this in all 3 DB engines.