
1.需要使用的模塊工具 from django.db import connection.queries # 用來查看ORM語句執行的sql語句以及執行時間
from django.db import reset_queries # 用來清空前面執行的sql
2.示例研究
假設有兩個模塊,多對一關系
class Process(models.Model):
...
class ProcessRun(models.Model):
process = models.ForeignKey(Process)
...
* 場景1:查詢指定ProcessRun對應的外鍵,Process對象下的字段屬性值
操作1:新人操作
c_process_run = ProcessRun.objects.filter(id=processrun_id)
if c_process_run.exists():
process_url = c_process_run[0].process.url
# 可以看到執行了兩條sql語句
{'time': '0.022', 'sql': 'SELECT * FROM `faconstor_processrun` WHERE `faconstor_processrun`.`id` = 100 LIMIT 1'},
{'time': '0.016', 'sql': 'SELECT *` FROM `faconstor_process` WHERE `faconstor_process`.`id` = 12'}
操作2:正確操作
c_process_run = ProcessRun.objects.filter(id=processrun_id).select_related("process") # 可以看到執行了一條sql語句,聯合查詢,節省了0.015秒
{'time': '0.023', 'sql': 'SELECT * FROM `faconstor_processrun` INNER JOIN `faconstor_process` ON (`faconstor_processrun`.`process_id` = `faconstor_process`.`id`) WHERE `faconstor_processrun`.`id` = 100 LIMIT 1'}]
* 衍生場景1:場景一中表示指定ProcessRun對象查詢,如果此時是遍歷ProcessRun查詢集呢?那么執行的sql次數就等同於查詢集的長度了,
假設100ProcessRun對象的查詢集,需要執行的sql時間次次疊加了!!!!!開玩笑呢?
# select_related()才是正確姿勢!
>>> c_process_run = ProcessRun.objects.filter(id__lte=100).select_related("process")
>>> for i in c_process_run:
... result.append({"name": i.process.name})
{'time': '0.042', 'sql': 'SELECT `faconstor_processrun`.`id`, `faconstor_processrun`.`process_id`, `faconstor_processrun`.`starttime`, `faconstor_processrun`.`endtime`, `faconstor_processrun`.`creatuser`, `faconstor_processrun`.`state`, `faconstor_processrun`.`run_reason`, `faconstor_processrun`.`note`, `faconstor_process`.`id`, `faconstor_process`.`code`, `faconstor_process`.`name`, `faconstor_process`.`remark`, `faconstor_process`.`sign`, `faconstor_process`.`rto`, `faconstor_process`.`rpo`, `faconstor_process`.`state`, `faconstor_process`.`sort`, `faconstor_process`.`url`, `faconstor_process`.`type`, `faconstor_process`.`color` FROM `faconstor_processrun` INNER JOIN `faconstor_process` ON (`faconstor_processrun`.`process_id` = `faconstor_process`.`id`) WHERE `faconstor_processrun`.`id` <= 100'}
* 衍生場景2:指定字段,並非所有。(但是不影響查詢時間)
c_process_run = ProcessRun.objects.filter(id__lte=100).select_related("process").only("process__name")
{'time': '0.023', 'sql': 'SELECT `faconstor_processrun`.`id`, `faconstor_processrun`.`process_id`, `faconstor_process`.`id`, `faconstor_process`.`name` FROM `faconstor_processrun` INNER JOIN `faconstor_process` ON (`faconstor_processrun`.`process_id` = `faconstor_process`.`id`) WHERE `faconstor_processrun`.`id` <= 100'}
********************* ORM連表查詢 ***********************
# 1.select_related()方法,可傳入兩個參數:外鍵對象名(並不是外鍵id),查詢深度depth(django默認會一定程度上拼命向下遞歸查詢,消耗很大);
# 假設StepRun表中包含Step表的外鍵關聯
c_step_run = StepRun.objects.select_related("step").all()[0]
# 如果再深一層:
c_step_run = StepRun.objects.select_related("step__外鍵中的外鍵對象名").all()[0]
# 相當於執行以下sql語句:
SELECT `faconstor_steprun`.`id`, `faconstor_steprun`.`step_id`, ... ...`faconstor_step`.`sort`, `faconstor_step`.`rto_
count_in`, `faconstor_step`.`remark` FROM `faconstor_steprun` LEFT OUTER JOIN `faconstor_step` ON (`faconstor_steprun`.`step_id` = `faconstor_step`.`id`) LIMIT 1'
# 如果沒有select_related()
# 你會有疑問:c_step_run = StepRun.objects.all()[0]
# 也可以通過上面的c_step_run對象查詢到Step表中的字段值:c_step_run.step.name
# 注意:ORM查詢語句不是取值的時候才執行的,並不是寫完上面的查詢,如果通過上面的方式,
# 除了執行取StepRun表數據的查詢sql外,還有多執行一次在Step表中的連表查詢,其效率可想而知。
# 2.prefetch_related()方法與select_related()方法的使用方式相同,區別在於select_related()用於一對一,多對一(指的是當前模型對象中包含ForeignKey外鍵,一對多指的是沒有ForeignKey的表),
# 而prefetch_related()用於多對多與一對多,但是盡量不要用而prefetch_related()用於一對多,效率低下。
# 如果想知道ORM查詢執行的sql,可以通過以下方式:
********************* 查看ORM查詢語句執行的sql語句方式 *****************
>> from faconstor.models import *
>> from django.db import connection, reset_queries
>> c_step_run = StepRun.objects.select_related("step").all()[0]
>> connection.queries
..
>> [{'time': '0.036', 'sql': 'SET SQL_AUTO_IS_NULL = 0'}, {'time': '0.039', 'sql': 'SELECT `faconst
or_steprun`.`id`, `faconstor_steprun`.`step_id`, `faconstor_steprun`.`processrun_id`, `faconstor
_steprun`.`starttime`, `faconstor_steprun`.`endtime`, `faconstor_steprun`.`operator`, `faconstor
_steprun`.`parameter`, `faconstor_steprun`.`result`, `faconstor_steprun`.`explain`, `faconstor_s
teprun`.`state`, `faconstor_steprun`.`note`, `faconstor_step`.`id`, `faconstor_step`.`process_id
`, `faconstor_step`.`last_id`, `faconstor_step`.`pnode_id`, `faconstor_step`.`code`, `faconstor_
step`.`name`, `faconstor_step`.`approval`, `faconstor_step`.`skip`, `faconstor_step`.`group`, `f
aconstor_step`.`time`, `faconstor_step`.`state`, `faconstor_step`.`sort`, `faconstor_step`.`rto_
count_in`, `faconstor_step`.`remark` FROM `faconstor_steprun` LEFT OUTER JOIN `faconstor_step` O
N (`faconstor_steprun`.`step_id` = `faconstor_step`.`id`) LIMIT 1'}]
# 還會顯示當前sql語句的執行時間
>> reset_queries()
# 在django項目終端輸出執行的SQL語句
# 只需要添加一下配置至settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}