fix: 加速抖音账单项目筛选 #152

Merged
qiuxiang merged 2 commits from fix/qiuxiang-douyin-bill-item-filter-performance into main 2026-09-10 13:33:48 +08:00
2 changed files with 70 additions and 7 deletions

View File

@ -72,13 +72,9 @@ class StoreReceivingAlipayBillMirrorRepository
$total = $useRecordedCount ? (int) $recordedCount : (clone $query)->count();
$summary = $this->summary($query, $filters, $channel);
$billRows = $query
->select('b.*')
->orderBy($sortColumn, $direction)
->orderBy('b.Id', $direction)
->forPage($page, $perPage)
->get()
->all();
$billRows = $this->pageRows(
$query, $sortColumn, $direction, $page, $perPage, $filters, $channel,
);
$shopNames = $this->shopNames($billRows);
$rows = collect($billRows)
->map(fn (object $row): array => $this->mapRowFor($row, $shopNames[(string) $row->shop_id] ?? null, $mapping))
@ -188,6 +184,49 @@ class StoreReceivingAlipayBillMirrorRepository
return $this->mirror->connection()->table('ops_jst_original_bill_info as b');
}
/** @return array<int,object> */
private function pageRows(
Builder $query,
string $sortColumn,
string $direction,
int $page,
int $perPage,
array $filters,
?string $channel,
): array {
if ($channel === null || ($filters['bill_item'] ?? '') === '') {
return $query->select('b.*')
->orderBy($sortColumn, $direction)
->orderBy('b.Id', $direction)
->forPage($page, $perPage)
->get()
->all();
}
$idQuery = clone $query;
if ($idQuery->getConnection()->getDriverName() === 'mysql') {
$idQuery->forceIndex('idx_original_bill_channel_shop');
}
$ids = $idQuery->select('b.Id')
->orderBy($sortColumn, $direction)
->orderBy('b.Id', $direction)
->forPage($page, $perPage)
->pluck('b.Id')
->all();
if ($ids === []) {
return [];
}
$rowsById = $this->billQuery()->whereIn('b.Id', $ids)->select('b.*')->get()
->keyBy(static fn (object $row): string => (string) $row->Id);
return collect($ids)
->map(static fn (mixed $id): ?object => $rowsById->get((string) $id))
->filter()
->values()
->all();
}
/** @return array{income:float,expense:float} */
private function summary(Builder $billQuery, array $filters, ?string $channel = null): array
{

View File

@ -318,6 +318,30 @@ class StoreReceivingAlipayBillMirrorRepositoryTest extends TestCase
$this->assertSame('1', $rows[0]['record_code']);
}
public function test_douyin_bill_item_filter_pages_through_ids_and_preserves_order(): void
{
$this->markReady();
$db = DB::connection('business_mirror');
$db->table('ops_jst_original_bill_info')->insert([
$this->row(1, 7, '2026-08-01 09:00:00', '1', 10, 'TouTiaoFXGZJ'),
$this->row(2, 7, '2026-08-03 09:00:00', '1', 20, 'TouTiaoFXGZJ'),
$this->row(3, 7, '2026-08-02 09:00:00', '1', 30, 'TouTiaoFXGZJ'),
]);
$db->flushQueryLog();
$db->enableQueryLog();
$result = (new StoreReceivingDouyinBillMirrorRepository($this->repository))->paginate(
['bill_item' => '交易佣'], 'occurred_at', 'desc', 1, 2,
);
$this->assertSame(['2', '3'], array_column($result['data'], 'record_code'));
$queries = $db->getQueryLog();
$this->assertCount(1, array_filter($queries, static fn (array $query): bool => str_contains($query['query'], 'select "b"."Id"')));
$this->assertCount(1, array_filter($queries, static fn (array $query): bool => str_contains($query['query'], 'select "b".*')
&& str_contains($query['query'], 'where "b"."Id" in')));
$db->disableQueryLog();
}
private function markReady(): void
{
foreach ([StoreReceivingAlipayBillMirrorRepository::DATASET, StoreReceivingAlipayBillMirrorRepository::SHOP_DATASET] as $dataset) {