如何删除Django冗余内部联接

时间:2018-07-18 02:34:32

标签: python mysql django inner-join

我正在使用Django,我需要使用多个模型来过滤数据的查询集。这些模型具有相同的外键字段。

示例:


    class Snp(models.Model):
        chromosome = models.IntegerField()
        position = models.IntegerField()

    class Variant(models.Model):
        snp = models.ForeignKey(Snp, on_delete=models.CASCADE)
        genotype = models.IntegerField()

    class Mutation(models.Model):
        snp = models.ForeignKey(Snp, on_delete=models.CASCADE)
        synonymous = models.IntegerField()

    class Annot(models.Model):
        snp = models.ForeignKey(Snp, on_delete=models.CASCADE)
        gene = models.IntegerField()


    q = Variant.objects.prefetch_related('snp').filter(snp__mutation__synonymous
    =1,snp__annot__gene=2)
    print(q.query)

这可能会创建以下SQL:


    SELECT "md_variant"."id", "md_variant"."snp_id", "md_variant"."genotype" FROM "md_variant"
    INNER JOIN "md_snp" ON ("md_variant"."snp_id" = "md_snp"."id")
    INNER JOIN "md_annot" ON ("md_snp"."id" = "md_annot"."snp_id")
    INNER JOIN "md_mutation" ON ("md_snp"."id" = "md_mutation"."snp_id")
    WHERE ("md_annot"."gene" = 2 AND "md_mutation"."synonymous" = 1)

我使用了比上面更快的简化SQL,并得到了相同的结果:


    SELECT "md_variant"."id", "md_variant"."snp_id", "md_variant"."genotype" FROM "md_variant"
    INNER JOIN "md_annot" ON ("md_variant"."snp_id" = "md_annot"."snp_id")
    INNER JOIN "md_mutation" ON ("md_variant"."snp_id" = "md_mutation"."snp_id") 
    WHERE ("md_annot"."gene" = 2 AND "md_mutation"."synonymous" = 1)

我认为内部联接md_snp是不必要的,因为同一模型Snp的Mutation,Variant和Annot模型外键。如何删除此多余的内部联接?

1 个答案:

答案 0 :(得分:0)

首先prefetch_related()在这里没有意义。

q = Variant.objects.filter(snp__mutation__synonymous=1, snp__annot__gene=2)
print(q.query)

您无法避免Join的Snp,因为您有ForeignKey SNP 。如果您认为您的sql查询更好,请执行原始sql查询。没问题。

Performing raw SQL queries in Django