Skip to content

Commit

Permalink
Merge pull request #29322 from nextcloud/mysql-search-ignore-index-21
Browse files Browse the repository at this point in the history
  • Loading branch information
skjnldsv authored Nov 4, 2021
2 parents 8469b44 + 5002bf9 commit 07c20b4
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 4 deletions.
17 changes: 17 additions & 0 deletions lib/private/DB/QueryBuilder/QueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -1301,4 +1301,21 @@ public function quoteAlias($alias) {

return $this->helper->quoteColumnName($alias);
}

/**
* Either appends to or replaces a single, generic query part.
*
* The available parts are: 'select', 'from', 'set', 'where',
* 'groupBy', 'having' and 'orderBy'.
*
* @param string $sqlPartName
* @param mixed $sqlPart
* @param bool $append
*
* @return $this This QueryBuilder instance.
*/
public function add(string $sqlPartName, $sqlPart, bool $append = false) {
$this->queryBuilder->add($sqlPartName, $sqlPart, $append);
return $this;
}
}
8 changes: 7 additions & 1 deletion lib/private/Files/Cache/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,13 @@ public function searchByMime($mimetype) {
protected function buildSearchQuery(ISearchQuery $searchQuery): IQueryBuilder {
$builder = $this->getQueryBuilder();

$query = $builder->selectFileCache('file');
// mysql really likes to pick an index for sorting if it can't fully satisfy the where
// filter with an index, since search queries pretty much never are fully filtered by index
// mysql often picks an index for sorting instead of the *much* more useful index for filtering.
//
// To bypass this, we tell mysql explicitly not to use the mtime (the default order field) index,
// so it will instead pick an index that is actually useful.
$query = $builder->selectFileCache('file', 'ignore index for order by (fs_mtime)');

$query->whereStorageId();

Expand Down
19 changes: 16 additions & 3 deletions lib/private/Files/Cache/CacheQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

namespace OC\Files\Cache;

use Doctrine\DBAL\Platforms\MySQLPlatform;
use OC\DB\QueryBuilder\QueryBuilder;
use OC\SystemConfig;
use OCP\DB\QueryBuilder\IQueryBuilder;
Expand All @@ -45,12 +46,24 @@ public function __construct(IDBConnection $connection, SystemConfig $systemConfi
$this->cache = $cache;
}

public function selectFileCache(string $alias = null) {
public function selectFileCache(string $alias = null, string $mysqlIndexHint = '') {
$name = $alias ? $alias : 'filecache';
$this->select("$name.fileid", 'storage', 'path', 'path_hash', "$name.parent", 'name', 'mimetype', 'mimepart', 'size', 'mtime',
'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum', 'metadata_etag', 'creation_time', 'upload_time')
->from('filecache', $name)
->leftJoin($name, 'filecache_extended', 'fe', $this->expr()->eq("$name.fileid", 'fe.fileid'));
->from('filecache', $name);
if ($mysqlIndexHint !== '' && $this->getConnection()->getDatabasePlatform() instanceof MySQLPlatform) {
$this->add('join', [
$this->quoteAlias($name) => [
// horrible query builder crimes to sneak in raw sql after the "FROM oc_filecache $name"
'joinType' => $mysqlIndexHint . ' left',
'joinTable' => $this->getTableName('filecache_extended'),
'joinAlias' => $this->quoteAlias('fe'),
'joinCondition' => $this->expr()->eq("$name.fileid", 'fe.fileid'),
],
], true);
} else {
$this->leftJoin($name, 'filecache_extended', 'fe', $this->expr()->eq("$name.fileid", 'fe.fileid'));
}

$this->alias = $name;

Expand Down

0 comments on commit 07c20b4

Please sign in to comment.