鍍金池/ 問答/Python  數(shù)據(jù)庫/ sqlalchemy 的查詢機制?

sqlalchemy 的查詢機制?

用 sqlalchemy 進行簡單的查詢:


# -*- coding:utf-8 -*-
__author__ = '東方鶚'
__blog__ = 'http://www.os373.cn'

from models import session, Employee, Department, DeptEmp, DeptManager, Salary, Title

# 初始化數(shù)據(jù)庫連接:
engine = create_engine('mysql+pymysql://root:password@127.0.0.1:3306/employees', echo=True)
# 創(chuàng)建DBSession類型:
DBSession = sessionmaker(bind=engine)
session = DBSession

data = session.query(Employee).all()
session.commit()

for d in data:
    print(d.emp_no, d.birth_date, d.first_name, d.last_name, d.gender, d.hire_date)

然后打印出來的結(jié)果如下:

圖片描述

根據(jù)圖片所示,難道 sqlalchemy 把所有的內(nèi)容查詢出來之后,如果要顯示每條的明細,還得從數(shù)據(jù)庫里一條一條的查詢出來嗎???

回答
編輯回答
敢試

sqlalchemy把所有內(nèi)容查詢出來后,顯示明細,確實是還需要從數(shù)據(jù)庫中一條一條的查詢出來。
只不過這個查詢不是從物理db中查詢,而是從虛擬內(nèi)存db中查詢。
(注:以下說法均為個人從日常實踐及對sqlalchemy的理解中得出的,官方具體怎么樣沒有實際佐證)

create_engine時會調(diào)用create_all()方法,這時將會在內(nèi)存中創(chuàng)建一個虛擬數(shù)據(jù)庫表。
查詢操作會將數(shù)據(jù)庫中的數(shù)據(jù)加載至內(nèi)存,調(diào)用明細時會對內(nèi)存中的表進行查詢操作。

# 1. 類似于下面的這種操作是不會觸發(fā)物理db的相關操作的,只是生成一段用于在物理db中執(zhí)行的sql
query_str = Model.query.filter(...).order_by(...).with_entities(...)

# 2. query_str執(zhí)行get()、all()、first()、one_or_none()等操作時,才會在鏈接物理db并執(zhí)行操作。
# 3. sqlalchemy會將返回結(jié)果保存至內(nèi)存中,最為緩存,供用戶查詢相關明細。
# 4. 至于查詢明細的方式,本質(zhì)上估計類似于dict.get(key)這種,具體的要看sqlalchemy以什么數(shù)據(jù)結(jié)構(gòu)
# 在內(nèi)存中保存查詢信息了,個人未關注過
# 5. db.commit()操作會觸發(fā)類似flush()的操作,這時會將緩存中的信息清空。例:
# 會在物理db中執(zhí)行select * from model where id = 1;
result = Model.query.get(1)
# 內(nèi)存中去查詢name,不會涉及到物理db
print result.name
# 內(nèi)存清空
db.commit()
# 兩步操作,①select * from model where id = 1;②從內(nèi)存中去拿name
print result.name

# 注:for循環(huán)等遍歷操作會默認觸發(fā)all()方法,例:
# 生成sql,select * from model;但未與物理db有相關交互。
query = Model.query
# 等價于 for res in query.all(),在物理db中執(zhí)行相關sql
for res in query:
# 從內(nèi)存中查詢id
print res.id

# 剛上邊那段瞎說了,請忽略,下面為更正信息
# 生成sql,select * from model;但未與物理db有相關交互。
# query現(xiàn)在為一個str,及query = 'select * from model'
query = Model.query
# 等價于 for res in query.all(),在物理db中執(zhí)行相關sql
# 現(xiàn)假設query中有三個結(jié)果[res1, res2, res3]
# 執(zhí)行完后query為查詢結(jié)果集合,query=[res1, res2, res3]
for res in query:
  # 從內(nèi)存中查詢id
  print res.id
# 清空緩存,但[res1, res2, res3]對象是保留的,及query=[res1, res2, res3]
db.commit()
# 等價于 for res in [res1, res2, res3]:
for res in query:
  # 兩部操作:①select * from model where id = res.id,從內(nèi)存中查詢id
  # 及commit后res1為detached狀態(tài),res.id后為attached狀態(tài)
  print res.id
2018年6月2日 01:23
編輯回答
忘了我

原來,加上all()會出現(xiàn)一條一條再查詢的問題,如果不加則沒有該問題?
不過對于 flask 如果你加上分頁,然后通過人工來一頁頁的查詢,倒是也不怎么影響性能!!!

2017年2月20日 03:00
編輯回答
久舊酒

在SQLAlchemy中一個Session(可以看作)是一個transaction,每個操作(基本上)對應一條或多條SQL語句,這些SQL語句需要發(fā)送到數(shù)據(jù)庫服務器才能被真正執(zhí)行,
附上大佬鏈接https://segmentfault.com/q/10...

2017年8月30日 04:25