将具有大IN子句的Django ORM查询转换为表值构造函数

时间:2018-06-21 04:42:56

标签: django postgresql django-orm django-postgresql

我有一些Django代码,以编程方式构建相对复杂的查询,其中各种过滤器通过一系列过滤器并排除调用而应用于初始数据集:

for filter in filters:
    if filter['name'] == 'revenue':
        accounts = accounts.filter(account_revenue__in: filter['values'])
    if filter['name'] == 'some_other_type':
        if filter['type'] == 'inclusion':
            accounts = accounts.filter(account__some_relation__in: filter['values'])
        if filter['type'] == 'exclusion':
            accounts = accounts.exclude(account__some_relation__in: filter['values'])
    ...etc

return accounts

在大多数情况下,过滤器的可能值相对较小且包含在内,因此Django ORM生成的IN子句足够有效。但是,在某些情况下,IN子句可能更大(10000至100K项)。

在普通的postgres中,我可以使用表值构造函数使此查询更加优化,例如:

SELECT domain 
FROM accounts 
INNER JOIN  ( 
    VALUES  ('somedomain.com'), ('anotherdomain.com'), ...etc 10K more times 
) VALS(v) ON accounts.domain=v

在原始查询中使用30K + IN子句,可能需要60秒钟以上的时间才能运行,而查询的表值版本则需要1秒的时间,

但是我无法弄清楚如何让Django ORM像我想要的那样构建查询,并且由于所有其他过滤器都是通过ORM过滤器构造的,所以我无法真正将整个内容编写为原始SQL。

我当时以为我可以获取将要运行Django ORM的原始SQL,进行正则表达式解析,但这似乎很脆弱(由于参数处理等原因,很难获得要运行的实际SQL,这令人惊讶。 )。我不知道如何用RawSQL注释,因为我不想添加要选择的列,而是想添加连接条件。有没有我想不到的简单解决方案?

0 个答案:

没有答案