[擴充套件包] Laravel-wherehasin 提升 ORM 關聯關係查詢效能 (優化 whereHas)

Jiangqh發表於2020-07-02

前幾天在QQ群裡看到有位同學請人幫忙根據社群裡的文章(給 Eloquent 的 whereHas 加個 where in 的優化)給EloquentwhereHas方法進行效能優化,因為這篇文章裡面提供的程式碼還是有些細節問題,並不能支援所有的關聯關係,所以我抽空寫了這個擴充套件包,支援了所有關聯關係。並且我也做了一些小測試,發現在資料量大的情況下優化過後的效能提升非常驚人,下面是一個簡單的測試,如果有不正確之處歡迎大家拍磚指正:

主表test_users寫入130002條資料,關聯表test_user_profiles寫入1002條資料,查詢程式碼如下

<?php
/**
 * 未優化sql
 * 
 * select * from `test_users` where exists
 *   (
 *     select * from `test_user_profiles` 
 *     where `test_users`.`id` = `test_user_profiles`.`user_id`
 *  ) 
 * limit 10
 */
$users1 = User::whereHas('profile')->limit(10)->get();

/**
 * 優化後的sql
 * 
 * select * from `test_users` where `test_users`.`id` in 
 *   (
 *     select `test_user_profiles`.`user_id` from `test_user_profiles` 
 *     where `test_users`.`id` = `test_user_profiles`.`user_id`
 *   ) 
 * limit 10
 */
$users1 = User::whereHasIn('profile')->limit(10)->get();

最終耗時如下,可以看出效能相差還是不小的,如果資料量更多一些,這個差距還會更大

whereHas (優化前)   0.50499701499939whereHasIn (優化後) 0.027166843414307

多測試幾次之後不難發現:

當主表資料量較多的情況下,where id in會有明顯的效能提升;當主表資料量較少的時候,兩者效能相差無幾。

簡介

Laravel wherehasin是一個可以提升Laravel ORM關聯關係查詢效能的擴充套件包,可以替代Laravel ORM中的whereHas以及whereHasMorphIn查詢方法。

Github (如果喜歡這個專案不妨點個star,謝謝支援~)

環境

  • PHP >= 7
  • laravel >= 5.5

安裝

composer require dcat/laravel-wherehasin

使用

whereHasIn

此方法已支援Laravel ORM中的所有關聯關係,可以替代whereHas

User::whereHasIn('profile')->get();

User::whereHasIn('profile', function ($q) {
    $q->where('id', '>', 10);
})->get();

orWhereHasIn

User::where('name', 'like', '%laravel%')->orWhereHasIn('profile')->get();

多級關聯關係

User::whereHasIn('painters.paintings', function ($q) {
    $q->whereIn('id', [600, 601]);
})->orderBy('id')->get()->toArray();

需要注意的是,如果是BelongsTo型別的關聯關係,使用whereHasIn時使用的不是主鍵,而是外來鍵

<?php

/**
 * 這裡用的是"user_id in",而不是"id in"
 * 
 * select * from `test_user_profiles` where `test_user_profiles`.`user_id` in 
 *   (
 *     select `test_users`.`id` from `test_users` where `test_user_profiles`.`user_id` = `test_users`.`id`
 *   )
 */
$profiles = Profile::whereHasIn('user')->get();

whereHasMorphIn

此方法已支援Laravel ORM中的所有關聯關係,可以替代whereHasMorph

Image::whereHasMorphIn('imageable', Post::class, function ($q) {
    $q->where('id', '>', 10);
})->get();

鳴謝

給 Eloquent 的 whereHas 加個 where in 的優化

本作品採用《CC 協議》,轉載必須註明作者和本文連結

Jiangqh

相關文章