python - 使用 SQLAlchemy 在 Postgres 中进行不区分大小写的索引

标签 python postgresql sqlalchemy

考虑一个带有索引 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/

相关文章:

excel - PostgreSQL 查询输出为 Excel 文件

postgresql:何时使用数组构造函数与大括号

python - 通过 Paramiko SSH 的 SQLAlchemy

python - 如何使用 Flask 和 SQLAlchemy 输出扁平化数据库表以实现出色表现

Python/Django 建模问题

python - 避免在终端中输入 "python"来打开 .py 脚本?

python - 如何制作只有文字的图例

sql - 查找列中具有重复值的行

python - Sqlalchemy:打印表的内容

python - 超过 1000 个主机的 pysnmp 扭曲客户端中的未处理错误