考虑一个带有索引的String
字段的声明性SQLAlchemy模型:
class User(Base):
name = Column(String(100), index=True, nullable=False)
name
字段区分大小写,这意味着应保留原始大小写,但应支持对索引进行有效的不区分大小写的查询。
实现此目标并在SQLAlchemy中实现的最佳方法是什么?
查询可以根据需要使用lower()
session.query(User).filter_by(name=lower('SOME_name'))
但是没关系,只要解决方案既优雅又高效。
由于性能要求,使用ILIKE
和Postgres级lower()
的查询是不可接受的,它们已经过测试,并且在我的用例中不能在大型表上执行得足够快。
答案 0 :(得分:2)
创建一个索引表达式LOWER(name)
的{{3}}:
Index('idx_user_name_lower', func.lower(User.name))
使用适当的索引查询,例如
session.query(User).filter(func.lower(User.name) == 'SOME_name'.lower())
如果LOWER(name)
具有高基数,可能会更好。
然后您可以将处理小写字母封装在functional index中:
# Verbatim from the documentation
class CaseInsensitiveComparator(Comparator):
def __eq__(self, other):
return func.lower(self.__clause_element__()) == func.lower(other)
class User(Base):
...
@hybrid_property
def name_insensitive(self):
return self.name.lower()
@name_insensitive.comparator
def name_insensitive(cls):
return CaseInsensitiveComparator(cls.name)
比较器将func.lower()
应用于幕后双方:
session.query(User).filter_by(name_insensitive='SOME_name')
等同于
session.query(User).filter(func.lower(User.name) == func.lower('SOME_name'))