
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',
},
}
}