最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

利用Python優(yōu)化數(shù)據(jù)庫(kù)N+1查詢問(wèn)題的方法詳解

 更新時(shí)間:2025年09月12日 08:57:58   作者:程序新視界  
N+1查詢問(wèn)題是一種常見(jiàn)的性能瓶頸,主要表現(xiàn)是應(yīng)用中需要執(zhí)行大量查詢,通常這是由于數(shù)據(jù)訪問(wèn)模式中的代碼結(jié)構(gòu)不佳導(dǎo)致的,本文將使用Python進(jìn)行這一問(wèn)題的優(yōu)化,需要的小伙伴可以了解下

數(shù)據(jù)庫(kù)之必備經(jīng)驗(yàn)視角:什么是N+1查詢問(wèn)題

N+1查詢問(wèn)題是一種常見(jiàn)的性能瓶頸,主要表現(xiàn)是應(yīng)用中需要執(zhí)行大量查詢。通常這是由于數(shù)據(jù)訪問(wèn)模式中的代碼結(jié)構(gòu)不佳導(dǎo)致的:先執(zhí)行一個(gè)查詢獲取記錄列表(1 查詢),然后針對(duì)每個(gè)記錄額外執(zhí)行多個(gè)單獨(dú)查詢(N 查詢)。這最終累積為 N+1 查詢問(wèn)題

雖然乍看之下,多個(gè)小型查詢似乎應(yīng)該比一個(gè)大型復(fù)雜查詢更輕量更快速,但實(shí)際上,多個(gè)查詢需要與數(shù)據(jù)庫(kù)進(jìn)行多次交互,包括發(fā)送查詢、數(shù)據(jù)庫(kù)處理查詢以及返回結(jié)果。

這不僅增加了延遲,還可能加重?cái)?shù)據(jù)庫(kù)的負(fù)擔(dān)。而一個(gè)復(fù)雜的單一查詢只需一次交互即可完成,并且往往可以通過(guò)數(shù)據(jù)庫(kù)引擎優(yōu)化執(zhí)行效率。

因此,從整體性能角度來(lái)看,多個(gè)小查詢通常比單次復(fù)雜查詢效率更低。

一個(gè) N+1 查詢的示例

以下是一個(gè)示例應(yīng)用場(chǎng)景。假設(shè)我們有兩張表,分別是 items 表和 categories 表:

表結(jié)構(gòu)如下

categories 表

idname
1Produce
2Deli
3Dairy

items 表

idnamecategory_id
1Apples1
2Cheese2
3BreadNULL

示例需求

我們希望應(yīng)用程序能夠列出所有商品,同時(shí)顯示它們所屬的分類(lèi)名稱。

第一種實(shí)現(xiàn)方式(存在 N+1 問(wèn)題)

例如,我們先查詢分類(lèi)列表,然后針對(duì)每個(gè)分類(lèi)的商品單獨(dú)執(zhí)行查詢(為了簡(jiǎn)化代碼,這里采用Python的實(shí)現(xiàn)方式):

import sqlite3
?
# 建立數(shù)據(jù)庫(kù)連接
conn = sqlite3.connect("example.db")
?
# 查詢分類(lèi)
categories_query = "SELECT * FROM categories;"
categories_cursor = conn.execute(categories_query)
?
for category in categories_cursor.fetchall():
    category_id = category[0]
    category_name = category[1]
?
    # 顯示分類(lèi)名稱
    print(f"Category: {category_name}")
    
    # 查詢?cè)摲诸?lèi)的商品
    items_query = "SELECT id, name FROM items WHERE category_id = ? ORDER BY name;"
    items_cursor = conn.execute(items_query, (category_id,))
    
    for item in items_cursor.fetchall():
        # 顯示商品 ID 和名稱
        print(f"  Item ID: {item[0]}, Item Name: {item[1]}")
?
conn.close()

這種方法邏輯簡(jiǎn)單易懂,適合小規(guī)模數(shù)據(jù)場(chǎng)景。然而,它的問(wèn)題是對(duì)每個(gè)分類(lèi)的商品都進(jìn)行了單獨(dú)查詢。假設(shè)分類(lèi)表有 N 條記錄,那么總共需要執(zhí)行 N+1 次查詢。面對(duì)大規(guī)模數(shù)據(jù)時(shí),查詢次數(shù)會(huì)急劇增多,導(dǎo)致響應(yīng)時(shí)間變長(zhǎng)。

性能對(duì)比:

假設(shè)數(shù)據(jù)庫(kù)中有 800 個(gè)商品和 17 個(gè)分類(lèi)表記錄,這種方法需要執(zhí)行 1 + 17 = 18 次查詢,耗時(shí)約為 1 秒。而通過(guò)結(jié)合復(fù)雜 SQL 查詢優(yōu)化,可以顯著減少查詢次數(shù)并減少時(shí)間消耗。

使用 JOIN 優(yōu)化 N+1 查詢

我們可以利用 SQL 的 JOIN 語(yǔ)句,將多個(gè)查詢合并為一個(gè)復(fù)雜查詢,從而避免 N+1 問(wèn)題。以下是優(yōu)化后的代碼:

import sqlite3
?
# 建立數(shù)據(jù)庫(kù)連接
conn = sqlite3.connect("example.db")
?
# 使用 JOIN 查詢分類(lèi)和商品
query = """
    SELECT 
        c.id AS category_id, 
        c.name AS category_name, 
        i.id AS item_id, 
        i.name AS item_name
    FROM categories c
    LEFT JOIN items i ON c.id = i.category_id
    ORDER BY c.name, i.name;
"""
cursor = conn.execute(query)
?
last_category_id = None
?
for row in cursor.fetchall():
    category_id = row[0]
    category_name = row[1]
    item_id = row[2]
    item_name = row[3]
?
    # 如果分類(lèi)發(fā)生變化,渲染分類(lèi)名稱
    if category_id != last_category_id:
        print(f"Category: {category_name}")
?
    # 顯示商品信息(如果存在)
    if item_id is not None:
        print(f"  Item ID: {item_id}, Item Name: {item_name}")
?
    last_category_id = category_id
?
conn.close()

通過(guò)上述代碼,我們將單次查詢的結(jié)果直接按分類(lèi)和商品合并,不再需要多次單獨(dú)查詢。響應(yīng)時(shí)間從 1 秒降低到 0.16 秒。在數(shù)據(jù)量較大時(shí),優(yōu)勢(shì)更加顯著。

數(shù)據(jù)結(jié)構(gòu)優(yōu)化與復(fù)雜查詢

對(duì)于更復(fù)雜的需求,比如需要展示分類(lèi)及其商品數(shù)量,可以利用 SQL 的 GROUP BY 進(jìn)行聚合查詢:

聚合查詢示例

query = """
    SELECT 
        c.id AS category_id, 
        c.name AS category_name, 
        COUNT(i.id) AS item_count
    FROM categories c
    LEFT JOIN items i ON c.id = i.category_id
    GROUP BY c.id, c.name
    ORDER BY c.name;
"""

復(fù)雜數(shù)據(jù)結(jié)構(gòu):分類(lèi)與商品列表

如果既需要商品數(shù)量,又需要展示商品詳細(xì)信息,我們可以在服務(wù)器端對(duì)查詢結(jié)果進(jìn)行組織,將其轉(zhuǎn)換為更符合應(yīng)用需求的數(shù)據(jù)結(jié)構(gòu)。例如,通過(guò)構(gòu)造 字典嵌套

import sqlite3
?
# 建立數(shù)據(jù)庫(kù)連接
conn = sqlite3.connect("example.db")
?
# 查詢分類(lèi)及商品數(shù)據(jù)
query = """
    SELECT 
        c.id AS category_id, 
        c.name AS category_name, 
        i.id AS item_id, 
        i.name AS item_name
    FROM categories c
    LEFT JOIN items i ON c.id = i.category_id
    ORDER BY c.name, i.name;
"""
cursor = conn.execute(query)
?
categories = {}
category_items = []
?
last_category_id = None
last_category_name = None
?
for row in cursor.fetchall():
    category_id = row[0]
    category_name = row[1]
    item_id = row[2]
    item_name = row[3]
?
    # 在分類(lèi)發(fā)生變化時(shí),將當(dāng)前分類(lèi)的商品數(shù)據(jù)存儲(chǔ)
    if last_category_id is not None and category_id != last_category_id:
        categories[last_category_name] = category_items
        category_items = []
?
    # 添加商品信息到當(dāng)前分類(lèi)
    if item_id is not None:
        category_items.append({"item_id": item_id, "item_name": item_name})
?
    last_category_id = category_id
    last_category_name = category_name
?
categories[last_category_name] = category_items
?
# 渲染數(shù)據(jù)
for category_name, items in categories.items():
    print(f"Category: {category_name}")
    print(f"{len(items)} items")
?
    for item in items:
        print(f"  Item ID: {item['item_id']}, Item Name: {item['item_name']}")
?
conn.close()

通過(guò)上述代碼,我們不僅解決了 N+1 查詢問(wèn)題,還生成了方便訪問(wèn)的嵌套數(shù)據(jù)結(jié)構(gòu),能夠快速查詢商品列表和商品數(shù)量。

總結(jié)

N+1 查詢問(wèn)題是一種典型的性能問(wèn)題,在大規(guī)模數(shù)據(jù)場(chǎng)景中尤為突出。通過(guò)優(yōu)化查詢結(jié)構(gòu)(如使用 JOIN 合并查詢)、設(shè)計(jì)高效的數(shù)據(jù)結(jié)構(gòu)以及理解查詢性能的影響,我們可以顯著提升應(yīng)用的響應(yīng)速度。

在實(shí)際項(xiàng)目中,避免 N+1 查詢問(wèn)題是性能優(yōu)化的核心之一,尤其是在涉及復(fù)雜關(guān)系和大量數(shù)據(jù)庫(kù)交互時(shí)。通過(guò)良好的代碼設(shè)計(jì)和合理的數(shù)據(jù)庫(kù)操作,我們不僅能提升性能,還能為后續(xù)功能開(kāi)發(fā)打下堅(jiān)實(shí)基礎(chǔ)。

到此這篇關(guān)于利用Python優(yōu)化數(shù)據(jù)庫(kù)N+1查詢問(wèn)題的方法詳解的文章就介紹到這了,更多相關(guān)數(shù)據(jù)庫(kù)N+1查詢優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python操作MongoDB的教程詳解(插,查,改,排,刪)

    Python操作MongoDB的教程詳解(插,查,改,排,刪)

    MongoDB是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù)。是一個(gè)介于關(guān)系數(shù)據(jù)庫(kù)和非關(guān)系數(shù)據(jù)庫(kù)之間的產(chǎn)品,是非關(guān)系數(shù)據(jù)庫(kù)當(dāng)中功能最豐富,最像關(guān)系數(shù)據(jù)庫(kù)的。本文將詳細(xì)和大家聊聊Python操作MongoDB的方法,需要的可以參考一下
    2022-09-09
  • Pycharm如何自動(dòng)生成頭文件注釋

    Pycharm如何自動(dòng)生成頭文件注釋

    這篇文章主要介紹了Pycharm如何自動(dòng)生成頭文件注釋,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • python實(shí)現(xiàn)低通濾波器代碼

    python實(shí)現(xiàn)低通濾波器代碼

    今天小編就為大家分享一篇python實(shí)現(xiàn)低通濾波器代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-02-02
  • Python刪除Java源文件中全部注釋的實(shí)現(xiàn)方法

    Python刪除Java源文件中全部注釋的實(shí)現(xiàn)方法

    這篇文章主要介紹了Python刪除Java源文件中全部注釋的實(shí)現(xiàn)方法,涉及Python讀取文件、正則匹配、字符串查找、替換等相關(guān)操作技巧,需要的朋友可以參考下
    2017-08-08
  • Python中的字符串相似度

    Python中的字符串相似度

    這篇文章主要介紹了Python中的字符串相似度,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • Python利用matplotlib生成圖片背景及圖例透明的效果

    Python利用matplotlib生成圖片背景及圖例透明的效果

    這篇文章主要給大家介紹了Python利用matplotlib生成圖片背景及圖例透明效果的相關(guān)資料,文中給出了詳細(xì)的示例代碼,相信對(duì)大家具有一定的參考家價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-04-04
  • Python列表的索引與切片

    Python列表的索引與切片

    這篇文章主要介紹了Python列表的索引與切片,索引用來(lái)對(duì)單個(gè)成員(元素)進(jìn)行訪問(wèn),切片則是對(duì)一定范圍內(nèi)的成員(元素)進(jìn)行訪問(wèn)。下文相關(guān)自來(lái)需要的小伙伴可以參考一下
    2022-04-04
  • python、java等哪一門(mén)編程語(yǔ)言適合人工智能?

    python、java等哪一門(mén)編程語(yǔ)言適合人工智能?

    哪一門(mén)編程語(yǔ)言適合人工智能?這篇文章主要為大家詳細(xì)介紹了python編程語(yǔ)言適合人工智能的原因、優(yōu)點(diǎn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Python?Flask框架實(shí)現(xiàn)小紅書(shū)圖片無(wú)水印解析下載

    Python?Flask框架實(shí)現(xiàn)小紅書(shū)圖片無(wú)水印解析下載

    這篇文章主要為大家介紹了Python?Flask框架實(shí)現(xiàn)小紅書(shū)圖片無(wú)水印解析下載,需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Pyqt5打開(kāi)電腦攝像頭進(jìn)行拍照的實(shí)現(xiàn)示例

    Pyqt5打開(kāi)電腦攝像頭進(jìn)行拍照的實(shí)現(xiàn)示例

    本文介紹了如何使用Pyqt5來(lái)控制攝像頭拍照,通過(guò)構(gòu)建一個(gè)簡(jiǎn)單的用戶界面,我們可以實(shí)現(xiàn)從攝像頭實(shí)時(shí)獲取圖像,保存圖片,感興趣的可以了解一下
    2023-08-08

最新評(píng)論

达拉特旗| 湄潭县| 西乡县| 樟树市| 衡东县| 平度市| 石首市| 铜陵市| 抚顺县| 玛沁县| 女性| 永德县| 安西县| 望谟县| 西畴县| 三门峡市| 扬州市| 东辽县| 广元市| 响水县| 仁怀市| 九龙县| 余江县| 腾冲县| 勃利县| 乐昌市| 西贡区| 建宁县| 阿合奇县| 定安县| 北川| 招远市| 县级市| 莒南县| 蓬安县| 白沙| 林口县| 定陶县| 桂林市| 白水县| 海伦市|