- 此问题在此处已有答案**:
MySQL SUM Query is extremely slow(3个答案)
2小时前关门了。
我正在Laravel 9项目中工作,用户可以购买"配额",然后在每次使用API时使用。但是,我需要每次检查用户的剩余配额,现在我的查询速度相当慢。
我有一个CreditTransaction
模型,该模型将每个事务存储在一个表中,该表包含一个user_id
和一个delta
列,这些列可能为正,也可能为负,具体取决于它们是否购买了配额或使用了配额。然后,我对credit_transactions
的hasMany
关系执行delta
列的sum
,这样就可以了。但是在查询时花费几秒钟来计算。
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable implements MustVerifyEmail
{
use HasApiTokens, HasFactory, Notifiable, TwoFactorAuthenticatable, SoftDeletes;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'role',
'first_name',
'last_name',
'email',
'timezone',
'password',
'origin_source',
'origin_source_other',
'origin_campaign',
'last_login_at',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
'two_factor_recovery_codes',
'two_factor_secret',
'origin_campaign',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'last_login_at' => 'datetime',
];
/**
* Get the credit transactions for the user
*
* @return int
*/
public function getCreditBalanceAttribute()
{
try {
if (!$this->credit_transactions) {
return 0;
}
$balance = $this->credit_transactions->sum('delta');
if ($balance <= 0) {
return 0;
}
return $balance;
} catch (\Exception $err) { }
return 0;
}
/**
* Get the credit transactions for the user
*
* @return array
*/
public function credit_transactions()
{
return $this->hasMany(CreditTransaction::class);
}
}
然后,我可以执行以下操作来获取当前余额。
Auth::user()->credit_balance
我不知道如何最好地处理这个问题,因为这是基于120k行的表大小,这是相当小的,同样,我需要信用余额是准确和快速的,所以缓存15分钟是不是一个选项。
这是我的credit_transactions
表:
Schema::create('credit_transactions', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->index();
$table->foreignId('credit_type_id')->default(1)->index();
$table->foreignUuid('message_id')->nullable()->index();
$table->integer('delta')->index();
$table->timestamps();
$table->softDeletes();
});
1条答案
按热度按时间rjee0c151#
更新您的方法以将事务处理总和获取为:
在此查看更多信息-Laravel Eloquent Sum of relation's column
要更快地运行sum(delta),需要在user_id和delta列上创建多列索引。
或者将其添加到您的Laravel迁移中:
dbfiddle example(每个用户20 k个事务)
sum
仅用了7 ms。是否可以更快地计算用户余额?
可以,但方法不同,创建一个存储实际用户余额的列,然后自动更新余额列,例如:
另请参见Is this SQL safe enough to handle user balance transaction?