日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
如何修復使用PythonORM工具SQLAlchemy時的常見陷阱

在使用 SQLAlchemy 時,那些看似很小的選擇可能對這種對象關系映射工具包的性能產(chǎn)生重要影響。

創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務,包含不限于網(wǎng)站設計、做網(wǎng)站、日照網(wǎng)絡推廣、成都小程序開發(fā)、日照網(wǎng)絡營銷、日照企業(yè)策劃、日照品牌公關、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務,您的肯定,是我們最大的嘉獎;創(chuàng)新互聯(lián)公司為所有大學生創(chuàng)業(yè)者提供日照建站搭建服務,24小時服務熱線:18980820575,官方網(wǎng)址:www.cdcxhl.com

對象關系映射Object-relational mapping(ORM)使應用程序開發(fā)人員的工作更輕松,在很大程度是因為它允許你使用你可能知道的語言(例如 Python)與數(shù)據(jù)庫交互,而不是使用原始 SQL 語句查詢。SQLAlchemy 是一個 Python ORM 工具包,它提供使用 Python 訪問 SQL 數(shù)據(jù)庫的功能。它是一個成熟的 ORM 工具,增加了模型關系、強大的查詢構造范式、簡單的序列化等優(yōu)點。然而,它的易用性使得人們很容易忘記其背后發(fā)生了什么。使用 SQLAlchemy 時做出的看似很小的選擇可能產(chǎn)生非常大的性能影響。

本文解釋了開發(fā)人員在使用 SQLAlchemy 時遇到的一些最重要的性能問題,以及如何解決這些問題。

只需要計數(shù)但檢索整個結果集

有時開發(fā)人員只需要一個結果計數(shù),但是沒有使用數(shù)據(jù)庫計數(shù)功能,而是獲取了所有結果,然后使用 Python 中的 len 完成計數(shù)。

 
 
 
  1. count = len(User.query.filter_by(acct_active=True).all())

相反,使用 SQLAlchemy 的 count 方法將在服務器端執(zhí)行計數(shù),從而減少發(fā)送到客戶端的數(shù)據(jù)。在前面的例子中調(diào)用 all() 也會導致模型對象的實例化,如果有很多數(shù)據(jù),那么時間代價可能會非常昂貴。

除非還需要做其他的事情,否則只需使用 count 方法:

 
 
 
  1. count = User.query.filter_by(acct_active=True).count()

只需要幾列時檢索整個模型

在許多情況下,發(fā)出查詢時只需要幾列數(shù)據(jù)。SQLAlchemy 可以只獲取你想要的列,而不是返回整個模型實例。這不僅減少了發(fā)送的數(shù)據(jù)量,還避免了實例化整個對象。使用列數(shù)據(jù)的元組而不是模型可以快得多。

 
 
 
  1. result = User.query.all()
  2. for user in result:
  3.     print(user.name, user.email)

反之,使用 with_entities 方法只選擇所需要的內(nèi)容:

 
 
 
  1. result = User.query.with_entities(User.name, User.email).all()
  2. for (username, email) in result:
  3.     print(username, email)

每次循環(huán)都更新一個對象

避免使用循環(huán)來單獨更新集合。雖然數(shù)據(jù)庫可以非??斓貓?zhí)行單個更新,但應用程序和數(shù)據(jù)庫服務器之間的往返時間將快速累加。通常,在合理的情況下爭取更少的查詢。

 
 
 
  1. for user in users_to_update:
  2.   user.acct_active = True
  3.   db.session.add(user)

改用批量更新方法:

 
 
 
  1. query = User.query.filter(user.id.in_([user.id for user in users_to_update]))
  2. query.update({"acct_active": True}, synchronize_session=False)

觸發(fā)級聯(lián)刪除

ORM 允許在模型關系上進行簡單的配置,但是有一些微妙的行為可能會令人吃驚。大多數(shù)數(shù)據(jù)庫通過外鍵和各種級聯(lián)選項維護關系完整性。SQLAlchemy 允許你使用外鍵和級聯(lián)選項定義模型,但是 ORM 具有自己的級聯(lián)邏輯,可以取代數(shù)據(jù)庫。

考慮以下模型:

 
 
 
  1. class Artist(Base):
  2.     __tablename__ = "artist"
  3.  
  4.     id = Column(Integer, primary_key=True)
  5.     songs = relationship("Song", cascade="all, delete")
  6.  
  7.  
  8. class Song(Base):
  9.     __tablename__ = "song"
  10.  
  11.     id = Column(Integer, primary_key=True)
  12.     artist_id = Column(Integer, ForeignKey("artist.id", ondelete="CASCADE"))

刪除歌手將導致 ORM 在 song 表上發(fā)出 delete 查詢,從而防止由于外鍵導致的刪除操作。這種行為可能會成為復雜關系和大量記錄的瓶頸。

請包含 passive_deletes 選項,以確保讓數(shù)據(jù)庫來管理關系。但是,請確保你的數(shù)據(jù)庫具有此功能。例如,SQLite 默認情況下不管理外鍵。

 
 
 
  1. songs = relationship("Song", cascade all, delete", passive_deletes=True)

當要使用貪婪加載時,應使用延遲加載

延遲加載是 SQLAlchemy 處理關系的默認方法。從上一個例子構建來看,加載一個歌手時不會同時加載他或她的歌曲。這通常是一個好主意,但是如果總是需要加載某些關系,單獨的查詢可能會造成浪費。

如果允許以延遲方式加載關系,像 Marshmallow 這樣流行的序列化框架可以觸發(fā)級聯(lián)查詢。

有幾種方法可以控制此行為。最簡單的方法是通過 relationship 函數(shù)本身。

 
 
 
  1. songs = relationship("Song", lazy="joined", cascade="all, delete")

這將導致一個左連接被添加到任何歌手的查詢中,因此,songs 集合將立即可用。盡管有更多數(shù)據(jù)返回給客戶端,但往返次數(shù)可能會少得多。

SQLAlchemy 為無法采用這種綜合方法的情況提供了更細粒度的控制,可以使用 joinedload() 函數(shù)在每個查詢的基礎上切換連接的加載。

 
 
 
  1. from sqlalchemy.orm import joinedload
  2.  
  3. artists = Artist.query.options(joinedload(Artist.songs))
  4. print(artists.songs) # Does not incur a roundtrip to load

使用 ORM 進行批量記錄導入

導入成千上萬條記錄時,構建完整模型實例的開銷會成為主要瓶頸。想象一下,從一個文件中加載數(shù)千首歌曲記錄,其中每首歌曲都先被轉換為字典。

 
 
 
  1. for song in songs:
  2.     db.session.add(Song(`song))

相反,繞過 ORM,只使用核心的 SQLAlchemy 參數(shù)綁定功能。

 
 
 
  1. batch = []
  2. insert_stmt = Song.__table__.insert()
  3. for song in songs:
  4.     if len(batch) > 1000:
  5.        db.session.execute(insert_stmt, batch)
  6.        batch.clear()
  7.     batch.append(song)
  8. if batch:
  9.     db.session.execute(insert_stmt, batch)

請記住,此方法會自然而然地跳過你可能依賴的任何客戶端 ORM 邏輯,例如基于 Python 的列默認值。盡管此方法比將對象加載為完整的模型實例要快,但是你的數(shù)據(jù)庫可能具有更快的批量加載方法。例如,PostgreSQL 的 COPY 命令為加載大量記錄提供了最佳性能。

過早調(diào)用提交或刷新

在很多情況下,你需要將子記錄與其父記錄相關聯(lián),反之亦然。一種顯然的方法是刷新會話,以便為有問題的記錄分配一個 ID。

 
 
 
  1. artist = Artist(name="Bob Dylan")
  2. song = Song(title="Mr. Tambourine Man")
  3.  
  4. db.session.add(artist)
  5. db.session.flush()
  6.  
  7. song.artist_id = artist.id

對于每個請求,多次提交或刷新通常是不必要的,也是不可取的。數(shù)據(jù)庫刷新涉及強制在數(shù)據(jù)庫服務器上進行磁盤寫入,在大多數(shù)情況下,客戶端將阻塞,直到服務器確認已寫入數(shù)據(jù)為止。

SQLAlchemy 可以在幕后跟蹤關系和管理相關鍵。

 
 
 
  1. artist = Artist(name="Bob Dylan")
  2. song = Song(title="Mr. Tambourine Man")
  3.  
  4. artist.songs.append(song)

總結

我希望這一系列常見的陷阱可以幫助你避免這些問題,并使你的應用平穩(wěn)運行。通常,在診斷性能問題時,測量是關鍵。大多數(shù)數(shù)據(jù)庫都提供性能診斷功能,可以幫助你定位問題,例如 PostgreSQL 的 pg_stat_statements 模塊。


當前名稱:如何修復使用PythonORM工具SQLAlchemy時的常見陷阱
網(wǎng)址分享:http://m.5511xx.com/article/cdcepio.html