您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Laravel8優(yōu)化數(shù)據(jù)庫(kù)查詢(xún)的技巧有哪些”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
本提示主要側(cè)重于提高處理大型數(shù)據(jù)集時(shí)應(yīng)用的內(nèi)存使用率。
處理大的集合時(shí),分組檢索結(jié)果處理,而不是一次性檢索處理。
如下展示了從 posts
表檢索數(shù)據(jù)的過(guò)程。
$posts = Post::all(); // 使用 eloquent
$posts = DB::table('posts')->get(); // 使用查詢(xún)構(gòu)造器
foreach ($posts as $post){
// 處理 posts 操作
}
上面的例子會(huì)從 posts 表檢索所有的記錄并處理。如果這個(gè)表達(dá)到了 100 多萬(wàn)行呢??jī)?nèi)存將很快被耗盡。
為了避免在處理大型數(shù)據(jù)集時(shí)出現(xiàn)問(wèn)題,我們可以檢索結(jié)果子集并按照下面的方式處理它們。
// 當(dāng)使用 eloquent 時(shí)
$posts = Post::chunk(100, function($posts){
foreach ($posts as $post){
// Process posts
}
});
// 當(dāng)使用查詢(xún)構(gòu)造器時(shí)
$posts = DB::table('posts')->chunk(100, function ($posts){
foreach ($posts as $post){
// Process posts
}
});
以上例子從 posts 表中檢索 100 條記錄對(duì)其進(jìn)行處理,另外再檢索 100 條記錄進(jìn)行處理。此迭代將繼續(xù),直到處理完所有記錄。
這種方法將創(chuàng)建更多的數(shù)據(jù)庫(kù)查詢(xún),但內(nèi)存效率會(huì)更高。 通常, 大型數(shù)據(jù)集的處理應(yīng)該再后臺(tái)進(jìn)行。因此,可以在后臺(tái)運(yùn)行時(shí)進(jìn)行更多查詢(xún),以避免在處理大型數(shù)據(jù)集時(shí)耗盡內(nèi)存。
// 使用 eloquent
foreach (Post::cursor() as $post){
// 處理單個(gè) post
}
// 使用 query 構(gòu)建器
foreach (DB::table('posts')->cursor() as $post){
// 處理單個(gè) post
}
示例進(jìn)行單個(gè)數(shù)據(jù)庫(kù)查詢(xún),檢索表的所有記錄,一個(gè)接一個(gè)一個(gè)處理 Eloquent 模型。這種方式僅查詢(xún)一次數(shù)據(jù)庫(kù),得到全部 posts 。 但使用 php 生成器 優(yōu)化內(nèi)存使用。
什么情況使用這個(gè)呢?
這能夠在應(yīng)用層極大地優(yōu)化內(nèi)存使用,由于我們檢索表的所有數(shù)據(jù),數(shù)據(jù)庫(kù)內(nèi)存占用任然很高。
在數(shù)據(jù)庫(kù)內(nèi)存較多,應(yīng)用內(nèi)存較少的時(shí)候,建議使用游標(biāo)。然而,如果你的數(shù)據(jù)庫(kù)沒(méi)有足夠的內(nèi)存,最好使用 chunks 。
// 使用 eloquent
$posts = Post::chunkById(100, function($posts){
foreach ($posts as $post){
// 處理 posts
}
});
// 使用 query 構(gòu)造器
$posts = DB::table('posts')->chunkById(100, function ($posts){
foreach ($posts as $post){
// 處理 posts
}
});
chunk
和 chunkById
最大的區(qū)別是 chunk 通過(guò)offset
和 limit
檢索數(shù)據(jù)。然而chunkById
通過(guò)id
字段檢索結(jié)構(gòu)。id 字段通常是整型字段,而且它也是自增字段。
chunk
和 chunkById
的查詢(xún)?nèi)缦隆?/p>
chunk
select * from posts offset 0 limit 100
select * from posts offset 101 limit 100
chunkById
select * from posts order by id asc limit 100
select * from posts where id > 100 order by id asc limit 100
通常,查詢(xún)使用 limit 和 offset 是較慢的,盡量避免使用。本文 詳細(xì)介紹使用 offset 的問(wèn)題。
chunkById 使用 id 整型字段,通過(guò) where clause
查詢(xún),這樣會(huì)更快。
什么時(shí)候使用 chunkById ?
當(dāng)數(shù)據(jù)庫(kù)存在自增 主鍵
的時(shí)候使用。
通常從數(shù)據(jù)庫(kù)檢索數(shù)據(jù)時(shí),會(huì)像下面這樣做。
$posts = Post::find(1); // 使用 eloquent
$posts = DB::table('posts')->where('id','=',1)->first(); // 使用 query 構(gòu)建器
上面的代碼會(huì)得到如下的查詢(xún)
select * from posts where id = 1 limit 1
select *
表示從表中查出所有列。
當(dāng)需要所有列時(shí),這沒(méi)有問(wèn)題。
然而,僅需要指定的列(id,title)時(shí),只需要像下面這樣檢索那些列。
$posts = Post::select(['id','title'])->find(1); // 使用 eloquent
$posts = DB::table('posts')->where('id','=',1)->select(['id','title'])->first(); // 使用 query 構(gòu)建器
上面代碼得到如下查詢(xún)
select id,title from posts where id = 1 limit 1
這點(diǎn)主要關(guān)注對(duì)檢索結(jié)果的處理時(shí)間。這不影響實(shí)際的查詢(xún)時(shí)間。
如我上面提到的,檢索指定的列,可以這樣做
$posts = Post::select(['title','slug'])->get(); // 使用 eloquent
$posts = DB::table('posts')->select(['title','slug'])->get(); // 使用 query 構(gòu)建器
執(zhí)行上面的代碼,它會(huì)在幕后執(zhí)行以下操作。
執(zhí)行 select title, slug from posts
查詢(xún)
檢索出的每一行對(duì)應(yīng)一個(gè) Post
模型對(duì)象(對(duì) PHP 對(duì)象)(query 構(gòu)建器得到標(biāo)準(zhǔn)的 PHP 對(duì)象)
為 Post
模型生成 collection
返回 collection
訪問(wèn)數(shù)據(jù)
foreach ($posts as $post){
// $post 是 Post 模型或 php 標(biāo)準(zhǔn)對(duì)象
$post->title;
$post->slug;
}
上面的方式有額外的開(kāi)銷(xiāo),為每一行創(chuàng)建 Post
模型,并為這些對(duì)象創(chuàng)建一個(gè)集合。如果的確需要 Post
模型實(shí)例而不是數(shù)據(jù),這是最正確的做法。
但如果您只需要兩個(gè)值時(shí),則可以執(zhí)行以下操作:
$posts = Post::pluck('title', 'slug'); // 使用 eloquent 時(shí)
$posts = DB::table('posts')->pluck('title','slug'); // 使用查詢(xún)構(gòu)造器時(shí)
當(dāng)上面代碼被執(zhí)行時(shí),它在幕后會(huì)執(zhí)行以下操作。
對(duì)數(shù)據(jù)庫(kù)執(zhí)行 select title, slug from posts
查詢(xún)
創(chuàng)建一個(gè)數(shù)組,其中會(huì)以 title
作為 數(shù)組值
,slug
作為 數(shù)組鍵
返回?cái)?shù)組 ( 數(shù)組格式:[ slug => title, slug => title ]
)
要訪問(wèn)結(jié)果,我們可以這么做
foreach ($posts as $slug => $title){
// $title 是 post 的 title
// $slug 是 post 的 slug
}
如果您想檢索一列,您可以這么做
$posts = Post::pluck('title'); // 使用 eloquent 時(shí)
$posts = DB::table('posts')->pluck('title'); // 使用查詢(xún)構(gòu)造器時(shí)
foreach ($posts as $title){
// $title 是 post 的 title
}
上面的方式消除了每一行 Post
對(duì)象的創(chuàng)建。這將降低查詢(xún)結(jié)果處理的內(nèi)存和時(shí)間消耗。
建議在新代碼中使用上述方式。個(gè)人感覺(jué)不值得花時(shí)間遵循上面的提示重構(gòu)代碼。
重構(gòu)代碼,最好是在要處理大的數(shù)據(jù)集或者是比較閑的時(shí)候
統(tǒng)計(jì)表的行數(shù),通常這樣做
$posts = Post::all()->count(); // 使用 eloquent
$posts = DB::table('posts')->get()->count(); // 使用查詢(xún)構(gòu)造器
這將生成以下查詢(xún)
select * from posts
上述方法將從表中檢索所有行。將它們加載到 collection
對(duì)象中并計(jì)算結(jié)果。當(dāng)數(shù)據(jù)表中的行較少時(shí),這可以正常工作。但隨著表的增長(zhǎng),內(nèi)存很快就會(huì)耗盡。
與上述方法不同,我們可以直接計(jì)算數(shù)據(jù)庫(kù)本身的總行數(shù)。
$posts = Post::count(); // 使用 eloquent 時(shí)
$posts = DB::table('posts')->count(); // 使用查詢(xún)構(gòu)造器時(shí)
這將生成以下查詢(xún)
select count(*) from posts
在 sql 中計(jì)算行數(shù)是一個(gè)緩慢的過(guò)程,當(dāng)數(shù)據(jù)庫(kù)表中有多行時(shí)性能會(huì)很差。最好盡量避免計(jì)算行數(shù)。
這條建議你可能聽(tīng)說(shuō)過(guò)無(wú)數(shù)次了。所以我會(huì)盡可能簡(jiǎn)短。讓我們假設(shè)您有以下場(chǎng)景
class PostController extends Controller
{
public function index()
{
$posts = Post::all();
return view('posts.index', ['posts' => $posts ]);
}
}
// posts/index.blade.php 文件
@foreach($posts as $post)
<li>
<h4>{{ $post->title }}</h4>
<p>Author: {{ $post->author->name }}</p>
</li>
@endforeach
上面的代碼是檢索所有的帖子,并在網(wǎng)頁(yè)上顯示帖子標(biāo)題和作者,假設(shè)帖子模型關(guān)聯(lián)作者
。
執(zhí)行以上代碼將導(dǎo)致運(yùn)行以下查詢(xún)。
select * from posts // 假設(shè)返回5條數(shù)據(jù)
select * from authors where id = { post1.author_id }
select * from authors where id = { post2.author_id }
select * from authors where id = { post3.author_id }
select * from authors where id = { post4.author_id }
select * from authors where id = { post5.author_id }
如上,1 條查詢(xún)來(lái)檢索帖子,5 條查詢(xún)來(lái)檢索帖子的作者(假設(shè)有 5 篇帖子)。因此對(duì)于每篇帖子,都會(huì)進(jìn)行一個(gè)單獨(dú)的查詢(xún)來(lái)檢索它的作者。
所以如果有 N 篇帖子,將會(huì)產(chǎn)生 N+1 條查詢(xún)(1 條查詢(xún)檢索帖子,N 條查詢(xún)檢索每篇帖子的作者)。這常被稱(chēng)作 N+1 查詢(xún)問(wèn)題。
避免這個(gè)問(wèn)題,可以像下面這樣預(yù)加載帖子的作者。
$posts = Post::all(); // Avoid doing this
$posts = Post::with(['author'])->get(); // Do this instead
執(zhí)行上面的代碼得到下面的查詢(xún):
select * from posts // Assume this query returned 5 posts
select * from authors where id in( { post1.author_id }, { post2.author_id }, { post3.author_id }, { post4.author_id }, { post5.author_id } )
從上面的例子,考慮作者歸屬于一個(gè)組,同時(shí)需要顯示組的名字的情況。因此在 blade 文件中,可以按下面這樣做。
@foreach($posts as $post)
<li>
<h4>{{ $post->title }}</h4>
<p>Author: {{ $post->author->name }}</p>
<p>Author's Team: {{ $post->author->team->name }}</p>
</li>
@endforeach
接著
$posts = Post::with(['author'])->get();
得到下面的查詢(xún):
select * from posts // Assume this query returned 5 posts
select * from authors where id in( { post1.author_id }, { post2.author_id }, { post3.author_id }, { post4.author_id }, { post5.author_id } )
select * from teams where id = { author1.team_id }
select * from teams where id = { author2.team_id }
select * from teams where id = { author3.team_id }
select * from teams where id = { author4.team_id }
select * from teams where id = { author5.team_id }
如上,盡管預(yù)加載了 authors
關(guān)系,仍然產(chǎn)生了大量的查詢(xún)。這是因?yàn)闆](méi)有預(yù)加載 authors
上的 team
關(guān)系。
通過(guò)下面這樣來(lái)解決這個(gè)它。
$posts = Post::with(['author.team'])->get();
執(zhí)行得到下面的查詢(xún)。
select * from posts // Assume this query returned 5 posts
select * from authors where id in( { post1.author_id }, { post2.author_id }, { post3.author_id }, { post4.author_id }, { post5.author_id } )
select * from teams where id in( { author1.team_id }, { author2.team_id }, { author3.team_id }, { author4.team_id }, { author5.team_id } )
通過(guò)預(yù)加載嵌套關(guān)系,可以將查詢(xún)數(shù)從 11 減到 3。
想象一下,有 posts
和 authors
兩張表。帖子表有 author_id
列歸屬作者表。
為了得到帖子的作者 id,通常這樣做
$post = Post::findOrFail(<post id>);
$post->author->id;
執(zhí)行得到兩個(gè)查詢(xún)。
select * from posts where id = <post id> limit 1
select * from authors where id = <post author id> limit 1
然而,可以直接通過(guò)下面方式得到作者 id 。
$post = Post::findOrFail(<post id>);
$post->author_id; // 帖子表有存放作者 id 的 author_id 列
什么時(shí)候采取上面的方式?
采取上的方式,需要確保帖子關(guān)聯(lián)的作者在作者表始終存在。
很多時(shí)候,一些數(shù)據(jù)庫(kù)查詢(xún)是不必要的。看看下面的例子。
<?php
class PostController extends Controller
{
public function index()
{
$posts = Post::all();
$private_posts = PrivatePost::all();
return view('posts.index', ['posts' => $posts, 'private_posts' => $private_posts ]);
}
}
上面代碼是從兩張不同的表(posts
, private_posts
)檢索數(shù)據(jù),然后傳到視圖中。
視圖文件如下。
// posts/index.blade.php
@if( request()->user()->isAdmin() )
<h3>Private Posts</h3>
<ul>
@foreach($private_posts as $post)
<li>
<h4>{{ $post->title }}</h4>
<p>Published At: {{ $post->published_at }}</p>
</li>
@endforeach
</ul>
@endif
<h3>Posts</h3>
<ul>
@foreach($posts as $post)
<li>
<h4>{{ $post->title }}</h4>
<p>Published At: {{ $post->published_at }}</p>
</li>
@endforeach
</ul>
正如你上面看到的,$private_posts
僅對(duì) 管理員
用戶可見(jiàn),其他用戶都無(wú)法看到這些帖子。
問(wèn)題是,當(dāng)我們?cè)谧?/p>
$posts = Post::all();
$private_posts = PrivatePost::all();
我們進(jìn)行兩次查詢(xún)。一次從 posts
表獲取記錄,另一次從 private_posts
表獲取記錄。
private_posts
表的記錄僅 管理員用戶
可見(jiàn)。但我們?nèi)栽诓樵?xún)以檢索所有用戶記錄,即使它們不可見(jiàn)。
我們可以調(diào)整邏輯,避免額外的查詢(xún)。
$posts = Post::all();
$private_posts = collect();
if( request()->user()->isAdmin() ){
$private_posts = PrivatePost::all();
}
將邏輯更改為上述內(nèi)容后,我們對(duì)管理員用戶進(jìn)行了兩次查詢(xún),并對(duì)其他用戶進(jìn)行了一次查詢(xún)。
我們有時(shí)需要進(jìn)行查詢(xún)以同一個(gè)表中檢索不同類(lèi)型的行。
$published_posts = Post::where('status','=','published')->get();
$featured_posts = Post::where('status','=','featured')->get();
$scheduled_posts = Post::where('status','=','scheduled')->get();
上述代碼正從同一個(gè)表檢索狀態(tài)不同的行。代碼將進(jìn)行以下查詢(xún)。
select * from posts where status = 'published'
select * from posts where status = 'featured'
select * from posts where status = 'scheduled'
如您所見(jiàn),它正在對(duì)同一個(gè)表進(jìn)行三次不同的查詢(xún)以檢索記錄。我們可以重構(gòu)此代碼以?xún)H進(jìn)行一次數(shù)據(jù)庫(kù)查詢(xún)。
$posts = Post::whereIn('status',['published', 'featured', 'scheduled'])->get();
$published_posts = $posts->where('status','=','published');
$featured_posts = $posts->where('status','=','featured');
$scheduled_posts = $posts->where('status','=','scheduled');
select * from posts where status in ( 'published', 'featured', 'scheduled' )
上面的代碼生成一個(gè)查詢(xún)來(lái)檢索全部特定狀態(tài)的帖子,通過(guò)狀態(tài)為返回的帖子創(chuàng)建不同的 collections 。三個(gè)不同的狀態(tài)的變量由一個(gè)查詢(xún)生成。
如果查詢(xún)中含有 where
條件作用于 string
類(lèi)型的 column
,最好給這列添加索引。通過(guò)這列的查詢(xún)將會(huì)快很多。
$posts = Post::where('status','=','published')->get();
上面例子,我們對(duì) status
列添加 where 條件來(lái)查詢(xún)??梢酝ㄟ^(guò)下面這樣的數(shù)據(jù)庫(kù)遷移來(lái)優(yōu)化查詢(xún)。
Schema::table('posts', function (Blueprint $table) {
$table->index('status');
});
分頁(yè)結(jié)果時(shí),我們通常會(huì)這樣做
$posts = Post::paginate(20);
這將進(jìn)行兩次查詢(xún),第一次檢索分頁(yè)結(jié)果,第二次表中計(jì)算表中的總行數(shù)。對(duì)表中的行數(shù)進(jìn)行計(jì)數(shù)是一個(gè)緩慢的操作,會(huì)對(duì)查詢(xún)性能產(chǎn)生負(fù)面影響。
那么為什么 laravel 會(huì)計(jì)算總行數(shù)呢?
為了生成分頁(yè)連接,Laravel 會(huì)計(jì)算總行數(shù)。因此,當(dāng)生成分頁(yè)連接時(shí),您可以預(yù)先知道會(huì)有多少頁(yè),以及過(guò)去的頁(yè)碼是多少。
另一方面,執(zhí)行 simplePaginate
不會(huì)計(jì)算總行數(shù),查詢(xún)會(huì)比 paginate
方法快得多。但您將無(wú)法知道最后一個(gè)頁(yè)碼并無(wú)法跳轉(zhuǎn)到不同的頁(yè)面。
如果您的數(shù)據(jù)庫(kù)表有很多行,最好避免使用 paginate
,而是使用 simplePaginate
。
$posts = Post::paginate(20); // 為所有頁(yè)面生成分頁(yè)鏈接
$posts = Post::simplePaginate(20); // 僅生成上一頁(yè)和下一頁(yè)的分頁(yè)鏈接
什么時(shí)候使用分頁(yè)和簡(jiǎn)單分頁(yè)
查看下面的比較表,確定是分頁(yè)還是簡(jiǎn)單分頁(yè)適合您
paginate / simplePaginate | |
---|---|
數(shù)據(jù)庫(kù)表只有很少行,并且不會(huì)變大 | paginate / simplePaginate |
數(shù)據(jù)庫(kù)表有很多行,并且增長(zhǎng)很快 | simplePaginate |
必須提供用戶選項(xiàng)以跳轉(zhuǎn)到特定頁(yè)面 | paginate |
必須向用戶顯示結(jié)果總數(shù) | paginate |
不主動(dòng)使用分頁(yè)鏈接 | simplePaginate |
UI/UX 不會(huì)影響從切換編號(hào)分頁(yè)鏈接到下一個(gè)/上一個(gè)分頁(yè)鏈接 | simplePaginate |
使用“加載更多”按鈕或“無(wú)限滾動(dòng)”分頁(yè) | simplePaginate |
當(dāng)嘗試查詢(xún)匹配特性模式的結(jié)果時(shí),我們通常會(huì)使用
select * from table_name where column like %keyword%
上述查詢(xún)導(dǎo)致全表掃描。如果我們知道出現(xiàn)在列值開(kāi)頭的關(guān)鍵字,我們會(huì)查詢(xún)以下結(jié)果。
select * from table_name where column like keyword%
最好避免在 where 子句中使用 SQL 函數(shù),因?yàn)樗鼈儠?huì)導(dǎo)致全表掃描。 讓我們看下面的例子。要根據(jù)特定的時(shí)間查詢(xún)結(jié)果,我們通常會(huì)這樣做
$posts = POST::whereDate('created_at', '>=', now() )->get();
這將導(dǎo)致類(lèi)似的于下面的查詢(xún)
select * from posts where date(created_at) >= 'timestamp-here'
上面的查詢(xún)將導(dǎo)致全表掃描,因?yàn)樵谟?jì)算日期
函數(shù)之前,不會(huì)應(yīng)用 where 條件。
我們可以重構(gòu)這個(gè)函數(shù),以避免使用如下的 date
sql 函數(shù)
$posts = Post::where('created_at', '>=', now() )->get();
select * from posts where created_at >= 'timestamp-here'
最好限制表中列的總數(shù)??梢岳孟?mysql 這樣的關(guān)系數(shù)據(jù)庫(kù)將具有如此多列的表拆分為多個(gè)表??梢允褂盟鼈兊闹麈I和外鍵將它們連接在一起。
向表中添加太多列會(huì)增加單個(gè)記錄的長(zhǎng)度,并且會(huì)減慢表掃描的速度。在執(zhí)行 select *
查詢(xún)時(shí),最終會(huì)檢索到一些實(shí)際上并不需要的列。
這個(gè)技巧來(lái)自個(gè)人經(jīng)驗(yàn),并不是設(shè)計(jì)數(shù)據(jù)庫(kù)表的標(biāo)準(zhǔn)方法。我建議只有當(dāng)您的表有太多的記錄或者會(huì)快速增長(zhǎng)時(shí)才遵循這個(gè)技巧。
如果一個(gè)表有存儲(chǔ)大量數(shù)據(jù)的列(例如: 數(shù)據(jù)類(lèi)型為 TEXT 的列) ,那么最好將它們分離到它們自己的表中,或者分離到一個(gè)不經(jīng)常被詢(xún)問(wèn)的表中。
當(dāng)表中有包含大量數(shù)據(jù)的列時(shí),單個(gè)記錄的大小會(huì)變得非常大。我個(gè)人觀察到它影響了我們其中一個(gè)項(xiàng)目的查詢(xún)時(shí)間。
假設(shè)您有一個(gè)名為 posts
的表,其中包含一列 內(nèi)容
,用于存儲(chǔ)博客文章內(nèi)容。博客文章的內(nèi)容將是真正的巨大和經(jīng)常的時(shí)候,你需要這個(gè)數(shù)據(jù)只有當(dāng)一個(gè)人正在查看這個(gè)特定的博客文章。
所以,在數(shù)據(jù)表中有大量文章記錄的時(shí)候,將這些長(zhǎng)文本字段(大字段)分離到單獨(dú)的表中將會(huì)徹底的改善查詢(xún)性能。
當(dāng)需要從一個(gè)數(shù)據(jù)表中查詢(xún)最新的記錄行時(shí),通常我們會(huì)這么做:
$posts = Post::latest()->get();
// or $posts = Post::orderBy('created_at', 'desc')->get();
上面的查詢(xún)方式將會(huì)產(chǎn)生如下 sql 語(yǔ)句:
select * from posts order by created_at desc
這種查詢(xún)方式基本上都是按照 created_at
字段做降序排列來(lái)給查詢(xún)結(jié)果排序的。由于 created_at
字段是字符串類(lèi)型的數(shù)據(jù),所以用這種方式對(duì)查詢(xún)結(jié)果進(jìn)行排序通常會(huì)更慢。(譯者注:MySQL 的 TIMESTAMP 類(lèi)型字段是以 UTC 格式存儲(chǔ)數(shù)據(jù)的,形如 20210607T152000Z,所以 created_at 字段確實(shí)是字符串類(lèi)型的數(shù)據(jù))。
如果你的數(shù)據(jù)表中使用了自增長(zhǎng)的 id
字段作為主鍵,那么大多數(shù)情況下,最新的數(shù)據(jù)記錄行的 id
字段值也是最大的。因?yàn)?id
字段不僅是一個(gè)整形數(shù)據(jù)的字段,而且也是一個(gè)主鍵字段,所以基于 id
字段對(duì)查詢(xún)結(jié)果進(jìn)行排序會(huì)更快。所以查詢(xún)最新記錄的最佳實(shí)踐如下:
$posts = Post::latest('id')->get();
// or $posts = Post::orderBy('id', 'desc')->get();
該方法會(huì)產(chǎn)生如下 sql 語(yǔ)句
select * from posts order by id desc
為了更快地從數(shù)據(jù)庫(kù)查詢(xún)數(shù)據(jù),我們已經(jīng)為 select
方法做了很多優(yōu)化。 大多數(shù)情況下,我們只需要為查詢(xún)方法進(jìn)行優(yōu)化就可以滿足性能要求了。 但是很多時(shí)候我們還需要為『插入』和『更新』(insert
和 update
)方法進(jìn)行優(yōu)化。所以我給大家推薦一篇有趣的文章optimizing mysql inserts,這篇文章將有助于優(yōu)化緩慢的『插入』和『更新』操作。
在 Laravel 框架中,優(yōu)化數(shù)據(jù)查詢(xún)并沒(méi)有完全通用的辦法。你只能盡量搞清楚下面這些問(wèn)題:你的程序是如何運(yùn)行的、進(jìn)行了多少個(gè)數(shù)據(jù)庫(kù)查詢(xún)操作、有多少查詢(xún)操作是真正必要的。所以請(qǐng)檢查你的應(yīng)用產(chǎn)生的查詢(xún)操作,這將有助于你確定并減少數(shù)據(jù)查詢(xún)操作的總量。
有很多工具可以輔助你檢查每個(gè)頁(yè)面產(chǎn)生的查詢(xún)方法:
注意: 不推薦在生產(chǎn)環(huán)境下使用這些工具。在生產(chǎn)環(huán)境使用這些工具將會(huì)降低你的應(yīng)用性能,并且會(huì)讓未經(jīng)授權(quán)的用戶獲取到程序的敏感信息。
Laravel Debugbar - Laravel Debugbar 有一個(gè) database
選項(xiàng)卡,點(diǎn)擊該選項(xiàng)卡將會(huì)展示你打開(kāi)一個(gè)頁(yè)面時(shí)應(yīng)用程序執(zhí)行的所有查詢(xún)語(yǔ)句。你可以瀏覽應(yīng)用的每個(gè)頁(yè)面并查看每個(gè)頁(yè)面用到的查詢(xún)語(yǔ)句。
Clockwork - Clockwork 與 Laravel Debugbar 一樣,只不過(guò) Clockwork 不會(huì)在你的網(wǎng)站上注入一個(gè)工具欄,你可以在『開(kāi)發(fā)者工具窗口』( developer tools window
),或者通過(guò)打開(kāi) url /yourappurl/clockwork
進(jìn)入一個(gè)單獨(dú)的頁(yè)面來(lái)查看應(yīng)用的調(diào)試信息。
Laravel Telescope - Laravel Telescope 是一個(gè)專(zhuān)為開(kāi)發(fā) Laravel 應(yīng)用而提供的十分優(yōu)秀的調(diào)試工具。一旦你安裝了 Laravel Telescope,便可以通過(guò)訪問(wèn) yourappurl/telescope
地址進(jìn)入它的儀表盤(pán)頁(yè)面。在 telescope 的儀表盤(pán)界面,點(diǎn)擊打開(kāi) queries
標(biāo)簽頁(yè),這個(gè)頁(yè)面將會(huì)展示你的應(yīng)用執(zhí)行過(guò)的所有 MySQL 查詢(xún)語(yǔ)句。
“Laravel8優(yōu)化數(shù)據(jù)庫(kù)查詢(xún)的技巧有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。