ORM連表查詢正確姿勢與查看sql查詢語句 | Django




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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM