使用 SQLAlchemy 优化过滤多个 SQL 计数子查询
Optimising filtering multiple SQL count sub queries with SQLAlchemy
我正在尝试将原始 postgres-SQL 转换为使用计数和过滤器的 sqlalchemy
SELECT
(
SELECT
COUNT(user_model.uuid)
FILTER ( WHERE email_vector @@ parse_websearch('search term'))
) AS email_vector,
(
SELECT
COUNT(user_model.uuid)
FILTER ( WHERE first_name_vector @@ parse_websearch('search term'))
) AS first_name_vector,
FROM
user_model
WHERE
(user_model.uuid = '20d7c90d-ebfa-4b04-9ee7-4fdedabc6c0b' AND all_vectors @@ parse_websearch('search term') )
效果很好而且速度非常快(低于 100 毫秒 - 即使过滤 20 个字段)
我将 sqlalchemy 编写为(简化)
search_query = []
search_vectors = [ email_vector, first_name_vector]
search_vector_names = [ 'email_vector', 'first_name_vector' ]
for search_vector, search_vector_name in zip(search_vectors, search_vector_names):
search_query.append(sa.sql.select(
sa.func.count(user_model.uuid)) \
.filter(search_vector.op('@@') \
(sa.func.parse_websearch(search_term))) \
.label(search_vector_name)
)
base_query = db.session.query(*search_query)
base_query = base_query.filter(user_model.uuid==user_uuid)
base_query = query.filter(search_vector.op('@@')(sa.func.parse_websearch(search_term))
这会产生以下结果 SQL
SELECT (
SELECT count(user_model.uuid) AS count_1
FROM user_model
WHERE user_model.email_vector @@ parse_websearch(%(parse_websearch_1)s)) AS email_vector,
(SELECT count(user_model.uuid) AS count_2
FROM user_model
WHERE user_model.first_name_vector @@ parse_websearch(%(parse_websearch_2)s)) AS first_name_vector,
WHERE user_model.uuid = %(uuid_1)s AND (user_model.all_vectors @@ parse_websearch(%(parse_websearch_30)s))
这有效但速度很慢(+1 秒)。我不确定为什么它这么慢或如何对子查询进行过滤查询。
我怀疑每个子查询都在执行 COUNT,其中 SQL 使用最终 WHERE 条件的过滤结果,但我不完全确定,我找不到任何过滤参考(我认为 CASE 是 shorthand?)在 sqlalchemy 文档中。我已经尝试将 .filter(user_model.uuid==uuid)
添加到 COUNT SQL 但它仍然很慢。
任何人都可以深入了解我所缺少的东西吗?
我最终使用 CASE
做到了这一点
case_stmt = sa.case(
[
(
full_text_search_vector.op('@@') \
(sa.func.parse_websearch(last_search_term)),1
)
]
).label(col_name)
query.append(case_stmt)
base_query = db.session.query(*query)
我正在尝试将原始 postgres-SQL 转换为使用计数和过滤器的 sqlalchemy
SELECT
(
SELECT
COUNT(user_model.uuid)
FILTER ( WHERE email_vector @@ parse_websearch('search term'))
) AS email_vector,
(
SELECT
COUNT(user_model.uuid)
FILTER ( WHERE first_name_vector @@ parse_websearch('search term'))
) AS first_name_vector,
FROM
user_model
WHERE
(user_model.uuid = '20d7c90d-ebfa-4b04-9ee7-4fdedabc6c0b' AND all_vectors @@ parse_websearch('search term') )
效果很好而且速度非常快(低于 100 毫秒 - 即使过滤 20 个字段)
我将 sqlalchemy 编写为(简化)
search_query = []
search_vectors = [ email_vector, first_name_vector]
search_vector_names = [ 'email_vector', 'first_name_vector' ]
for search_vector, search_vector_name in zip(search_vectors, search_vector_names):
search_query.append(sa.sql.select(
sa.func.count(user_model.uuid)) \
.filter(search_vector.op('@@') \
(sa.func.parse_websearch(search_term))) \
.label(search_vector_name)
)
base_query = db.session.query(*search_query)
base_query = base_query.filter(user_model.uuid==user_uuid)
base_query = query.filter(search_vector.op('@@')(sa.func.parse_websearch(search_term))
这会产生以下结果 SQL
SELECT (
SELECT count(user_model.uuid) AS count_1
FROM user_model
WHERE user_model.email_vector @@ parse_websearch(%(parse_websearch_1)s)) AS email_vector,
(SELECT count(user_model.uuid) AS count_2
FROM user_model
WHERE user_model.first_name_vector @@ parse_websearch(%(parse_websearch_2)s)) AS first_name_vector,
WHERE user_model.uuid = %(uuid_1)s AND (user_model.all_vectors @@ parse_websearch(%(parse_websearch_30)s))
这有效但速度很慢(+1 秒)。我不确定为什么它这么慢或如何对子查询进行过滤查询。
我怀疑每个子查询都在执行 COUNT,其中 SQL 使用最终 WHERE 条件的过滤结果,但我不完全确定,我找不到任何过滤参考(我认为 CASE 是 shorthand?)在 sqlalchemy 文档中。我已经尝试将 .filter(user_model.uuid==uuid)
添加到 COUNT SQL 但它仍然很慢。
任何人都可以深入了解我所缺少的东西吗?
我最终使用 CASE
做到了这一点 case_stmt = sa.case(
[
(
full_text_search_vector.op('@@') \
(sa.func.parse_websearch(last_search_term)),1
)
]
).label(col_name)
query.append(case_stmt)
base_query = db.session.query(*query)