【发布时间】:2010-11-23 15:42:58
【问题描述】:
Django 1.3-dev 提供了几种使用原始 SQL 查询数据库的方法。它们被覆盖here 和here。推荐的方法是使用.raw() 或.extra() 方法。这样做的好处是,如果检索到的数据符合 Model,您仍然可以直接使用它的某些功能。
我要显示的页面有些复杂,因为它使用了大量信息,这些信息分布在具有不同关系(one2one、one2many)的多个表中。使用当前方法,服务器每页必须执行大约 4K 查询。由于数据库到网络服务器的通信,这显然很慢。
一种可能的解决方案是使用原始 SQL 来检索相关数据,但由于查询的复杂性,我无法将其转换为 Django 中的等价物。
查询是:
SELECT clin.iso as iso,
(SELECT COUNT(*)
FROM clin AS a
LEFT JOIN clin AS b
ON a.pat_id = b.pat_id
WHERE a.iso = clin.iso
) AS multiple_iso,
(SELECT COUNT(*)
FROM samptopat
WHERE samptopat.iso_id = clin.iso
) AS multiple_samp,
(SELECT GROUP_CONCAT(value ORDER BY snp_id ASC)
FROM samptopat
RIGHT JOIN samptosnp
USING(samp_id)
WHERE iso_id = clin.iso
GROUP BY samp_id
LIMIT 1 -- Return 1st samp only
) AS snp
FROM clin
WHERE iso IN (...)
或者WHERE iso = ...。
示例输出如下所示:
+-------+--------------+---------------+-------------+
| iso | multiple_iso | multiple_samp | snp |
+-------+--------------+---------------+-------------+
| 7 | 19883 | 0 | NULL |
| 8 | 19883 | 0 | NULL |
| 21092 | 1 | 2 | G,T,C,G,T,G |
| 31548 | 1 | 0 | NULL |
+-------+--------------+---------------+-------------+
4 rows in set (0.00 sec)
documentation 解释了如何使用WHERE col = %s 而不是IN 语法进行查询。
这个问题的一部分是如何使用 Django 和 IN 语句执行原始 SQL 查询?
另一部分是,考虑以下模型:
class Clin(models.Model):
iso = models.IntegerField(primary_key=True)
pat = models.IntegerField(db_column='pat_id')
class Meta:
db_table = u'clin'
class SampToPat(models.Model):
samptopat_id = models.IntegerField(primary_key=True)
samp = models.OneToOneField(Samp, db_column='samp_id')
pat = models.IntegerField(db_column='pat_id')
iso = models.ForeignKey(Clin, db_column='iso_id')
class Meta:
db_table = u'samptopat'
class Samp(models.Model):
samp_id = models.IntegerField(primary_key=True)
samp = models.CharField(max_length=8)
class Meta:
db_table = u'samp'
class SampToSnp(models.Model):
samptosnp_id = models.IntegerField(primary_key=True)
samp = models.ForeignKey(Samp, db_column='samp_id')
snp = models.IntegerField(db_column='snp_id')
value = models.CharField(max_length=2)
class Meta:
db_table = u'samptosnp'
是否可以将上述查询重写为更面向 ORM 的内容?
【问题讨论】:
-
首先,我会删除显式主键,django 无论如何都使用整数。
-
看起来这是指向一个现有的数据库;因此他需要指定主键,因为它们的名称已经不是
id。我想知道的是,Clin和SampToPat都引用了pat_id,但我没有看到与Pat对应的模型。我也没有看到Snp的模型为了完整性,你不应该包括那些模型吗?我不禁想到,如果我们有可用的Pat模型,我们也许能够想出处理其中一些聚合函数的方法。 -
@Jordan,是的,模型存在,但由于我没有在当前查询中直接使用它们,为了简单起见,我删除了这些关系。您能否详细说明为什么相关模型的存在会使聚合函数更易于使用? ID 还不够吗?
-
@Evgeny,正如 Jordan 猜测的那样,这是一个遗留设置,并非所有字段都遵循 Django 约定。
-
我明白,只是想向自己解释问题:)
标签: sql mysql django django-models query-optimization