Skip to content

Commit 07c20b4

Browse files
authored
Merge pull request #29322 from nextcloud/mysql-search-ignore-index-21
2 parents 8469b44 + 5002bf9 commit 07c20b4

File tree

3 files changed

+40
-4
lines changed

3 files changed

+40
-4
lines changed

lib/private/DB/QueryBuilder/QueryBuilder.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,4 +1301,21 @@ public function quoteAlias($alias) {
13011301

13021302
return $this->helper->quoteColumnName($alias);
13031303
}
1304+
1305+
/**
1306+
* Either appends to or replaces a single, generic query part.
1307+
*
1308+
* The available parts are: 'select', 'from', 'set', 'where',
1309+
* 'groupBy', 'having' and 'orderBy'.
1310+
*
1311+
* @param string $sqlPartName
1312+
* @param mixed $sqlPart
1313+
* @param bool $append
1314+
*
1315+
* @return $this This QueryBuilder instance.
1316+
*/
1317+
public function add(string $sqlPartName, $sqlPart, bool $append = false) {
1318+
$this->queryBuilder->add($sqlPartName, $sqlPart, $append);
1319+
return $this;
1320+
}
13041321
}

lib/private/Files/Cache/Cache.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,13 @@ public function searchByMime($mimetype) {
848848
protected function buildSearchQuery(ISearchQuery $searchQuery): IQueryBuilder {
849849
$builder = $this->getQueryBuilder();
850850

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

853859
$query->whereStorageId();
854860

lib/private/Files/Cache/CacheQueryBuilder.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
namespace OC\Files\Cache;
2828

29+
use Doctrine\DBAL\Platforms\MySQLPlatform;
2930
use OC\DB\QueryBuilder\QueryBuilder;
3031
use OC\SystemConfig;
3132
use OCP\DB\QueryBuilder\IQueryBuilder;
@@ -45,12 +46,24 @@ public function __construct(IDBConnection $connection, SystemConfig $systemConfi
4546
$this->cache = $cache;
4647
}
4748

48-
public function selectFileCache(string $alias = null) {
49+
public function selectFileCache(string $alias = null, string $mysqlIndexHint = '') {
4950
$name = $alias ? $alias : 'filecache';
5051
$this->select("$name.fileid", 'storage', 'path', 'path_hash', "$name.parent", 'name', 'mimetype', 'mimepart', 'size', 'mtime',
5152
'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum', 'metadata_etag', 'creation_time', 'upload_time')
52-
->from('filecache', $name)
53-
->leftJoin($name, 'filecache_extended', 'fe', $this->expr()->eq("$name.fileid", 'fe.fileid'));
53+
->from('filecache', $name);
54+
if ($mysqlIndexHint !== '' && $this->getConnection()->getDatabasePlatform() instanceof MySQLPlatform) {
55+
$this->add('join', [
56+
$this->quoteAlias($name) => [
57+
// horrible query builder crimes to sneak in raw sql after the "FROM oc_filecache $name"
58+
'joinType' => $mysqlIndexHint . ' left',
59+
'joinTable' => $this->getTableName('filecache_extended'),
60+
'joinAlias' => $this->quoteAlias('fe'),
61+
'joinCondition' => $this->expr()->eq("$name.fileid", 'fe.fileid'),
62+
],
63+
], true);
64+
} else {
65+
$this->leftJoin($name, 'filecache_extended', 'fe', $this->expr()->eq("$name.fileid", 'fe.fileid'));
66+
}
5467

5568
$this->alias = $name;
5669

0 commit comments

Comments
 (0)