【发布时间】:2013-06-04 20:05:09
【问题描述】:
在我的 Django 应用程序中,我需要像这样生成一个 MySQL 查询:
SELECT * FROM player WHERE (myapp_player.sport_id = 4 AND (myapp_player.last_name LIKE 'smi%'))
UNION
SELECT * FROM player WHERE (myapp_player.sport_id = 4 AND (myapp_player.first_name LIKE 'smi%'));
我不能使用 Q 对象来 OR 一起 __istartswith 过滤器,因为 Django ORM 生成的查询不使用 UNION 并且它的运行速度至少比上面的 UNION 查询慢 40 倍。对于我的应用程序,这种性能是无法接受的。
所以我正在尝试这样的事情:
Player.objects.raw("SELECT * FROM myapp_player WHERE (sport_id = %%s AND (last_name LIKE '%%s%')) UNION SELECT * FROM sports_player WHERE (sport_id = %%s AND (first_name LIKE '%%s%'))", (sport.id, qword, sport.id, qword))
我为冗长的单行代码道歉,但我想在尝试调试此类问题时避免使用三引号字符串。
当我执行或 repr 这个查询集对象时,我得到如下异常:
*** ValueError: unsupported format character ''' (0x27) at index 133
这是单引号中的单引号,而不是三引号。如果我去掉 LIKE 子句周围的单引号,那么我会得到关于 LIKE 子句后面的 close-paren ) 字符的类似异常。
显然 Django 和 MySQL 在此查询的正确语法上存在分歧,但是否有适用于两者的语法?
最后,我也不确定用于字符串插值的 %%s 语法是否正确。 Django 文档建议我应该能够在 raw() 的参数中使用常规的 %s 语法,但是一些在线资源建议使用 %%s 或 ?作为原始 SQL 中字符串插值的占位符。
衷心感谢您对这个问题的一点点澄清!
【问题讨论】:
-
在您的原始查询中,将
sport_id = %%s更改为sport_id = %s。我怀疑这会解决问题,但它是无效的语法 -
我相信您必须转义
%符号,因此您在查询中想要的每个百分号都应该是first_name LIKE %%%s%%另外使用 LIKE 查询不会扩展,我会研究全文索引为您的后端,或使用全文搜索引擎之一 -
@jsarets 试试这个dpaste.com/hold/1211374
-
我不知道为什么您在使用 OR 时会出现性能下降。您是否针对
SELECT * FROM player WHERE (myapp_player.sport_id = 4 AND ((myapp_player.last_name LIKE 'smi%') OR (myapp_player.first_name LIKE 'smi%')))之类的查询测试过联合查询的性能?原始 SQL 确实应该是不得已而为之的功能。另外,您是否考虑将 index=True 添加到 first_name 和 last_name 列?如果你这样做,你会在这个查询上看到相当大的性能提升。