mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 17:01:16 +00:00
Try to fix slow search query
This commit is contained in:
@@ -103,29 +103,37 @@ class ReleaseSearchService
|
||||
// Get order by clause
|
||||
$orderBy = $this->getBrowseOrder($orderBy === '' ? 'posted_desc' : $orderBy);
|
||||
|
||||
// Build final SQL with pagination
|
||||
$sql = sprintf(
|
||||
'SELECT * FROM (%s) r ORDER BY r.%s %s LIMIT %d OFFSET %d',
|
||||
$baseSql,
|
||||
$orderBy[0], // @phpstan-ignore offsetAccess.notFound
|
||||
$orderBy[1], // @phpstan-ignore offsetAccess.notFound
|
||||
$limit,
|
||||
$offset
|
||||
);
|
||||
$pagedIdsSql = $this->buildSearchPageIdsSql($whereSql, $orderBy, $limit, $offset);
|
||||
|
||||
// Check cache
|
||||
$cacheKey = md5($this->getCacheVersion().$sql);
|
||||
$cacheKey = md5($this->getCacheVersion().$pagedIdsSql.$baseSql);
|
||||
$releases = Cache::get($cacheKey);
|
||||
if ($releases !== null) {
|
||||
return $releases;
|
||||
}
|
||||
|
||||
// Execute query
|
||||
$releases = Release::fromQuery($sql);
|
||||
$pagedIds = array_map(
|
||||
static fn (object $row): int => (int) $row->id,
|
||||
DB::select($pagedIdsSql)
|
||||
);
|
||||
|
||||
if ($pagedIds === []) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
$pageWhereSql = sprintf('WHERE r.id IN (%s)', implode(',', $pagedIds));
|
||||
$detailSql = sprintf(
|
||||
'SELECT * FROM (%s) r ORDER BY FIELD(r.id, %s)',
|
||||
$this->buildSearchBaseSql($pageWhereSql),
|
||||
implode(',', $pagedIds)
|
||||
);
|
||||
|
||||
// Execute query for the final page only.
|
||||
$releases = Release::fromQuery($detailSql);
|
||||
|
||||
// Add total count for pagination
|
||||
if ($releases->isNotEmpty()) {
|
||||
$releases[0]->_totalrows = $this->getPagerCount($baseSql);
|
||||
$releases[0]->_totalrows = $this->getReleasesCountForWhere($whereSql);
|
||||
}
|
||||
|
||||
// Cache results
|
||||
@@ -1209,6 +1217,40 @@ class ReleaseSearchService
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the lightweight page-ID query for web search.
|
||||
* This keeps the expensive joins out of the ORDER BY/LIMIT phase.
|
||||
*
|
||||
* @param array<string, mixed> $orderBy
|
||||
*/
|
||||
private function buildSearchPageIdsSql(string $whereSql, array $orderBy, int $limit, int $offset): string
|
||||
{
|
||||
return sprintf(
|
||||
'SELECT r.id FROM releases r %s ORDER BY r.%s %s LIMIT %d OFFSET %d',
|
||||
$whereSql,
|
||||
$orderBy[0], // @phpstan-ignore offsetAccess.notFound
|
||||
$orderBy[1], // @phpstan-ignore offsetAccess.notFound
|
||||
$limit,
|
||||
$offset
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total number of matching web-search releases without the expensive detail joins.
|
||||
*/
|
||||
private function getReleasesCountForWhere(string $whereSql): int
|
||||
{
|
||||
return $this->getPagerCount($this->buildSearchCountSql($whereSql));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the releases-only count query for web search pagination.
|
||||
*/
|
||||
private function buildSearchCountSql(string $whereSql): string
|
||||
{
|
||||
return sprintf('SELECT COUNT(*) as count FROM releases r %s', $whereSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the passworded releases clause.
|
||||
*/
|
||||
|
||||
@@ -130,4 +130,44 @@ class ReleaseSearchServiceOrderingTest extends TestCase
|
||||
$this->assertSame(550, $method->invoke($this->service, 50, 50));
|
||||
$this->assertSame(2000, $method->invoke($this->service, 2500, 50));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the paged ID query only selects release IDs from the releases table.
|
||||
*/
|
||||
public function test_build_search_page_ids_sql_uses_releases_only(): void
|
||||
{
|
||||
$reflection = new ReflectionClass(ReleaseSearchService::class);
|
||||
$method = $reflection->getMethod('buildSearchPageIdsSql');
|
||||
|
||||
$sql = $method->invoke(
|
||||
$this->service,
|
||||
'WHERE r.passwordstatus = 0 AND r.id IN (1,2,3)',
|
||||
['postdate', 'desc'],
|
||||
50,
|
||||
0
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
'SELECT r.id FROM releases r WHERE r.passwordstatus = 0 AND r.id IN (1,2,3) ORDER BY r.postdate desc LIMIT 50 OFFSET 0',
|
||||
$sql
|
||||
);
|
||||
$this->assertStringNotContainsString('JOIN', $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the lightweight count query is built directly against releases.
|
||||
*/
|
||||
public function test_build_search_count_sql_uses_releases_only_count_query(): void
|
||||
{
|
||||
$reflection = new ReflectionClass(ReleaseSearchService::class);
|
||||
$method = $reflection->getMethod('buildSearchCountSql');
|
||||
|
||||
$sql = $method->invoke($this->service, 'WHERE r.passwordstatus = 0 AND r.id IN (1,2,3)');
|
||||
|
||||
$this->assertSame(
|
||||
'SELECT COUNT(*) as count FROM releases r WHERE r.passwordstatus = 0 AND r.id IN (1,2,3)',
|
||||
$sql
|
||||
);
|
||||
$this->assertStringNotContainsString('JOIN', $sql);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user