为什么订阅会 100% 加载处理器
Why do subscriptions load the processor 100%
我通过以下方式从 hasura 获取统计数据
前端(nuxt.js)
<script>
import subUsers from '~/apollo/subscriptions/stats/users'
import users from '~/apollo/queries/stats/users'
export default {
apollo: {
users: {
query: users,
update: data => data.users_aggregate.aggregate.count,
subscribeToMore: {
document: subUsers,
updateQuery: (previousResult, { subscriptionData }) => {
return {
users_aggregate: subscriptionData.data.users_aggregate
}
}
}
}
}
}
</script>
哈苏拉:
query users {
users_aggregate {
aggregate {
count
}
}
}
subscription users {
users_aggregate {
aggregate {
count
}
}
}
在 table user
我有大约 500,000 个用户
并且由于订阅,我已 100% 加载所有处理器内核
Hasura 通过基于时间间隔的轮询实现订阅,这基本上意味着您的查询是每 1 秒 运行。您可以在此处阅读有关架构决策的详细信息:
由于您运行每秒对 50 万行进行聚合查询,那么...
那你能做什么? Postgres 恰好为您提供了解决方案,它被称为物化视图。您可以根据所需的聚合创建一个这样的视图,然后告诉 PG 仅在有意义时更新它。所以在你的情况下,你会在每次添加或删除用户时更新它。然后你订阅你的视图,它的成本基本上是零(因为视图会记住查询结果直到更新)。
您希望订阅查询能够非常快速地工作。使其快速的一种方法是在每次更改后缓存计数本身。您可以在您的用户 table 上使用触发器来实现这一点。缓存的值存储在 user_aggregate
table 中,您现在可以在其上订阅。例如:
drop table if exists user_aggregate;
drop trigger if exists user_aggregate_trigger on user_info;
drop function if exists user_aggregate();
create table user_aggregate (
id int not null primary key,
user_aggregate int not null
);
create or replace function user_aggregate()
returns trigger
as $$
begin
insert into user_aggregate (id, user_aggregate)
values (1, (select count(id) from user_info))
on conflict (id) do
update set user_aggregate = excluded.user_aggregate;
return new;
end
$$ language plpgsql;
create trigger user_aggregate_trigger
after insert or delete on user_info
for each row execute procedure user_aggregate();
insert into user_aggregate (id, user_aggregate)
values (1, (select count(id) from user_info))
on conflict (id) do
update set user_aggregate = excluded.user_aggregate;
如果您批量 inserting/deleting 很多用户,您可能想要禁用触发器。
我通过以下方式从 hasura 获取统计数据
前端(nuxt.js)
<script>
import subUsers from '~/apollo/subscriptions/stats/users'
import users from '~/apollo/queries/stats/users'
export default {
apollo: {
users: {
query: users,
update: data => data.users_aggregate.aggregate.count,
subscribeToMore: {
document: subUsers,
updateQuery: (previousResult, { subscriptionData }) => {
return {
users_aggregate: subscriptionData.data.users_aggregate
}
}
}
}
}
}
</script>
哈苏拉:
query users {
users_aggregate {
aggregate {
count
}
}
}
subscription users {
users_aggregate {
aggregate {
count
}
}
}
在 table user
我有大约 500,000 个用户
并且由于订阅,我已 100% 加载所有处理器内核
Hasura 通过基于时间间隔的轮询实现订阅,这基本上意味着您的查询是每 1 秒 运行。您可以在此处阅读有关架构决策的详细信息:
由于您运行每秒对 50 万行进行聚合查询,那么...
那你能做什么? Postgres 恰好为您提供了解决方案,它被称为物化视图。您可以根据所需的聚合创建一个这样的视图,然后告诉 PG 仅在有意义时更新它。所以在你的情况下,你会在每次添加或删除用户时更新它。然后你订阅你的视图,它的成本基本上是零(因为视图会记住查询结果直到更新)。
您希望订阅查询能够非常快速地工作。使其快速的一种方法是在每次更改后缓存计数本身。您可以在您的用户 table 上使用触发器来实现这一点。缓存的值存储在 user_aggregate
table 中,您现在可以在其上订阅。例如:
drop table if exists user_aggregate;
drop trigger if exists user_aggregate_trigger on user_info;
drop function if exists user_aggregate();
create table user_aggregate (
id int not null primary key,
user_aggregate int not null
);
create or replace function user_aggregate()
returns trigger
as $$
begin
insert into user_aggregate (id, user_aggregate)
values (1, (select count(id) from user_info))
on conflict (id) do
update set user_aggregate = excluded.user_aggregate;
return new;
end
$$ language plpgsql;
create trigger user_aggregate_trigger
after insert or delete on user_info
for each row execute procedure user_aggregate();
insert into user_aggregate (id, user_aggregate)
values (1, (select count(id) from user_info))
on conflict (id) do
update set user_aggregate = excluded.user_aggregate;
如果您批量 inserting/deleting 很多用户,您可能想要禁用触发器。