itsource

REST API에 대한 Larabel DB 쿼리가 매우 느립니다.

mycopycode 2022. 9. 25. 00:23
반응형

REST API에 대한 Larabel DB 쿼리가 매우 느립니다.

라라벨과 함께 첫 걸음을 내딛고 음악 재생 목록을 작성하려고 합니다.데이터베이스에는 다음 3개의 엔티티/모델이 있습니다.

Play <-n-1-> Song <-n-1-> Artist

테이블 생성:

        Schema::create('plays', function (Blueprint $table) {
            $table->id();
            $table->bigInteger('song_id')->unsigned();
            $table->foreign('song_id')
                ->references('id')
                ->on('songs')
                ->onDelete('cascade');
            $table->dateTimeTz('date');
            $table->bigInteger('station_id')->unsigned();
            $table->foreign('station_id')
                ->references('id')
                ->on('stations');
            $table->timestamps();

            $table->unique(['song_id', 'date']);
        });

        Schema::create('songs', function (Blueprint $table) {
            $table->id();
            $table->bigInteger('artist_id')->unsigned();
            $table->foreign('artist_id')
                ->references('id')
                ->on('artists')
                ->onDelete('cascade');
            $table->string('title');
            $table->string('cover_url')->nullable();
            $table->smallInteger('cover_width')->nullable();
            $table->smallInteger('cover_height')->nullable();
            $table->string('asin')->nullable();
            $table->date('last_cover_check')->nullable();
            $table->timestamps();

            $table->unique(['artist_id', 'title']);
        });

        Schema::create('artists', function (Blueprint $table) {
            $table->id();
            $table->string('name')->unique();
            $table->timestamps();
        });

데이터베이스에는 약 85만6000곡의 플레이와 33000곡의 곡, 15000명의 아티스트가 있습니다.

처음에는 plays-> songs-> artist를 열심히 로드하여 직접 모델을 사용하려고 했습니다.

return PlayResource::collection(Play::whereDate('date', $date)->get());

Larabel 경유 REST API에 대한 이 쿼리는 인섬니아를 사용하여 2.6초 걸립니다.이건 너무 느린 것 같아요.

Larabel을 올바르게 이해하면 많은 DB 쿼리에 영향을 미칩니다.

  • 재생에 대한 단일 쿼리
  • 노래에 대한 또 다른 노래
  • 하지만 모든 연극/노래에 대해 아티스트에 대한 별도의 질문(?)이 있습니다.

그래서 하나의 JOIN 쿼리를 생성하여 하나의 DB 쿼리를 가지려고 했습니다.

return DB::table('plays')
    ->leftJoin('songs', 'plays.song_id', '=', 'songs.id')
    ->leftJoin('artists', 'songs.artist_id', '=', 'artists.id')
    ->select('plays.*', 'songs.*', 'artists.*')
    ->whereDate('plays.date', $date)
    ->orderByDesc('plays.date')
    ->get();

이 쿼리는 조금 빠르지만 여전히 느립니다: 2.2s

DB에서 직접 호출되는 동등한 SQL 쿼리가 훨씬 빠릅니다.

SELECT *
FROM plays p
LEFT JOIN songs s ON p.song_id = s.id
LEFT JOIN artists a ON s.artist_id = a.id
WHERE DATE(p.date) = "2020-12-30"
ORDER BY p.date DESC;

-> 0.4초

Laravel을 사용할 때 발생하는 일반적인 오버헤드입니까?

편집 1:

네, 찾았습니다.DB::getQueryLog()(하지만 그건 내가 찾던 게 아니었어)이제 알겠다:신속한 로딩이 연결된 테이블을 3개 사용하면 DB 쿼리는 3개만 발생합니다.첫 번째는 400ms로 가장 느리다.2개의 쿼리는 각각 1~2ms밖에 걸리지 않습니다.

라라벨보다 빠를 루멘도 찾았어요.그래서 해봤어요.모델을 사용한 첫 번째 쿼리는 1.4초입니다.출력 매핑에 Json Resources를 추가하면 0.3초 -> 1.7초가 추가됩니다.내 생각에 이 모든 것은 여전히 느리다.

하지만 저는 이것이 현대적 프레임워크로 지불해야 하는 가격이라고 생각합니다.(2006년 이전 재생 목록에서는 프레임워크를 사용하지 않습니다.)

EDIT2: 첫 번째 쿼리는 다음과 같이 대폭 강화됩니다.

  1. 인덱스 추가date기둥.
  2. 및 함수를 사용하지 않고 쿼리합니다(DATE(`date`)또는->whereDate('date', ...))를 대신해서->whereBetween('date', [$date, $date.' 23:59:59'])이제 첫 번째 쿼리는 5ms(이전 400ms에서)밖에 걸리지 않습니다.루멘 질의는 모두 1.3점입니다

SQL 쿼리에 걸리는 시간은 현재 10ms 미만입니다.따라서 루멘 오버헤드는 약 99%입니다.통증이 아주 심해요.더 많은 튜닝 가능성을 찾아보겠습니다.

EDIT3 Rust(actix_web, diesel)를 사용하여 동일한 REST API를 작성했으며 동일한 DB를 사용하여 동일한 요청에는 16ms가 소요됩니다.이 PHP 프레임워크가 너무 느리다니 말도 안 돼.이제 Rust에 초점을 맞춰 백엔드의 PHP/Larabel/Lumen을 드롭하겠습니다.

Larabel이 데이터베이스에 대해 실행 중인 쿼리를 확인하려면 앱/프로바이더/AppServiceProvider.php 파일에 다음 함수를 추가합니다.

public function boot(){
        if(env('APP_DEBUG')) {
            DB::listen(function($query) {
                File::append(
                    storage_path('/logs/query.log'),
                    $query->sql . ' [' . implode(', ', $query->bindings) . ']' . PHP_EOL
            );
            });
        }
    }

작성되는 /storage/logs/query.log 파일에 각 쿼리의 SQL 코드가 있습니다.이를 통해 쿼리 빌더의 스테이트먼트를 이해하고 최적화할 수 있었습니다.때로는 비슷한 문제가 있었습니다.

언급URL : https://stackoverflow.com/questions/65576827/laravel-db-query-for-rest-api-very-slow

반응형