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