从我的Laravel数据库中遍历1000个条目需要很长时间

时间:2019-05-30 16:21:07

标签: php laravel laradock

我正在设置一个api端点,该端点负责从数据库中获取电影。我与流派有很多关系。它们与数据透视表连接。在尝试通过响应将所有电影发送之前,我试图将它们分类。 Chrome浏览器显示它占用了7 + s TTFB(第一个字节的时间)。我需要知道减速在哪里发生。我还用Postman测试了端点并显示了相同的结果。我不知道我在关系方面做错了什么,遍历数据库,获取数据。

我正在使用Laradock提供Mysql,PHP,NGINX。我试图打破循环,以便每个流派组中只能有10部电影。这样做使我的时间从20多秒-> 7多秒缩短了。

有: 11种类型 1300电影 3205 genre_movie

数据库示例 电影:

 |id|name|...|
 |1 |mov1|...|
 |2 |mov2|...|
 |3 |mov3|...|
 |4 |mov4|...|

类型:

|id|genre   |...|
|1 |action  |...|
|2 |drama   |...|
|3 |thriller|...|
|4 |cartoon |...|

数据透视:流派电影

|movie_id|genre_id|
|1       |1       |
|1       |2       |
|2       |2       |
|3       |4       |

这是我的关系 类型:

    public function movie(){
        return $this->belongsToMany('App\Movie');
    }

电影:

    public function genre(){
        return $this->belongsToMany('App\Genre');
    }

这是我的移民 电影:

    public function up()
    {
        Schema::create('movies', function (Blueprint $table) {
            $table->bigIncrements('id')->unsigned();
            $table->string('title', 100);
            $table->text('synopsis');
            $table->integer('released_year');
            $table->string('imdb_url', 100);
            $table->string('s3_location', 100);
            $table->string('poster_location', 100);
            $table->boolean('isRestricted');
            $table->timestamps();
        });
    }

类型:

    public function up()
    {
        Schema::create('genres', function (Blueprint $table) {
            $table->bigIncrements('id')->unsigned();
            $table->string('genre');
            $table->longText('description');
        });
    }

genre_movie:

    public function up()
    {
        Schema::create('genre_movie', function (Blueprint $table) {
            $table->bigInteger('genre_id')->unsigned();
            $table->foreign('genre_id')->references('id')->on('genres');

            $table->bigInteger('movie_id')->unsigned();
            $table->foreign('movie_id')->references('id')->on('movies');
        });

这是我播种数据的方式: 电影工厂

$factory->define(App\Movie::class, function (Faker $faker) {
    $faker->addProvider(new Image($faker));
    $faker->addProvider(new Base($faker));
    return [
        //
        'title' => $faker->name,
        'synopsis' => $faker->paragraph,
        'poster_location' => $faker->imageUrl($width=680, $height=680),
        'imdb_url' => 'https://www.imdb.com/title/tt5884052/',
        's3_location' => 'movie.mp4',
        'released_year' => $faker->numberBetween($min=1900, $max=1960),
        'isRestricted' => $faker->numberBetween($min=0, $max=1)
    ];
});

GenreTable播种器

    public function run()
    {
        //

        $genres = ['action', 'adventure', 'comedy', 'crime','drama','fantasy','historical','horror','romance','science fiction','thriller'];
        $seeds = [];
        foreach($genres as $genre){
            array_push($seeds,[
                'genre' => $genre,
                'description' => Str::random(150)
            ]);

        }
        DB::table('genres')->insert($seeds);

    }

MovieTable播种器

    public function run()
    {
        //
        $this->call([GenreSeeder::class]);
        factory(App\Movie::class, 1300)->create();

        $genres = App\Genre::all();

        App\Movie::all()->each(function ($movie) use ($genres) {
            $movie->genre()->attach(
                $genres->random(rand(1,4))->pluck('id')->toArray()
            );
        });

    }

Api路线

    Route::get('movies/filteredByGenre', 'MovieController@filteredByGenre');

MovieController @ filteredByGenre

    public function filteredByGenre(Request $request){

        $movies = Movie::with('genre:genre')->get();
        $sizeofMovies = count($movies);
        $formatedMovie = [];

        $count = 0;
        for($x = 0; $x < $sizeofMovies; $x++){
            $sizeofGenre = count($movies[$x]->genre);
            for($y = 0; $y < $sizeofGenre; $y++){
                $genre = $movies[$x]->genre[$y];
                try{
                    if(isset($formatedMovie[$genre['genre']])){
                        if(sizeof($formatedMovie[$genre['genre']]) > 10){
                            break;
                        }
                        $formatedMovie[$genre['genre']][] = $movies[$x];
                    }else{
                        $formatedMovie[$genre['genre']][] = $movies[$x];
                    }
                } catch(ErrorException $e) {
                    $formatedMovie[$genre['genre']][] = $movies[$x];
                }

            }
        }
        $response = ['success' => true, 'data' => $formatedMovie ];
        return response()->json($response, 201);
    }

我如何在前端接收数据

    componentDidMount() {
        var url = '/api/movies/filteredByGenre';
        axios
            .get(url)
            .then(response => {
                return response.data;
            })
            .then(json => {
                console.log(json);
                this.setState({ frontPageMovies: json.data });
            });
    }

用于启动服务器并植入代码的命令

docker-compose up -d nginx mysql phpmyadmin workspace
php artisan db:seed --class=MoviesTableSeeder

我希望电影按流派排序,检索数据所需的时间不超过1-3秒。

2 个答案:

答案 0 :(得分:0)

如果您的表都没有索引,我将从那里开始。通常,只需在主列上添加索引和/或主键(在这种情况下为ID),就可以大大提高性能。您可以将它们想像成一本书的索引...确保您可以扫描每一页,但是如果您能掌握所有内容的位置,则扫描速度会更快。

Schema::create('movies', function (Blueprint $table) {
    $table->bigIncrements('id')->primary();
    ... or ...
    $table->index(['id']);
});

我还建议从https://github.com/barryvdh/laravel-debugbar安装或启用Laravel调试栏。这可以向您显示幕后应用程序中发生的情况,包括每个数据库查询以及完成这些查询所花费的时间。在开发工具中有点像TTFB,但对于Chrome看不到的东西。

我经常使用的最后一个选择是让Laravel生成数据库查询但不执行它...

$movies = Movie::with('genre:genre')->toSql();

...,然后直接在我的数据库(phpMyAdmin或您首选的控制台)中执行它。如果速度很快,我知道它是我的php代码。否则,我知道我需要查看其他数据库优化。

答案 1 :(得分:0)

问题是我如何从数据库中检索数据。我以前使用的方式检索数据花费的时间太长。我将查询切换到:

        $movies = DB::table('genre_movie')
        ->select('movies.*')
        ->addSelect('genres.genre')
        ->join('movies','genre_movie.movie_id','=','movies.id')
        ->join('genres','genre_movie.genre_id','=','genres.id')
        ->get();

我太新了,不明白为什么。我认为这是我建立数据库,模型或关系的方式;我不确定。 现在我的页面加载时间不到1秒。

如果有人可以评论为什么会这样,那将很有帮助。我知道,雄辩的人可以非常轻松地处理大量数据。