考虑一个带有索引 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()
的查询是 Not Acceptable ,它们已经过测试并且在大型表上执行速度不够快用例。
最佳答案
创建一个 functional index索引表达式 LOWER(name)
:
Index('idx_user_name_lower', func.lower(User.name))
有了索引就可以查询
session.query(User).filter(func.lower(User.name) == 'SOME_name'.lower())
如果 LOWER(name)
具有高基数,可能会表现更好。
然后您可以将小写处理封装在 custom comparator 中:
# 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'))
关于python - 使用 SQLAlchemy 在 Postgres 中进行不区分大小写的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53063778/