身份验证类型
id | 名字 |
---|---|
uuid | varchar |
主键 | |
0aa4d9a9-e024-4792-bc41-36a4f3528d36 | 密码 |
账户
id | 电子邮件 | 密码 | ...其他几列 | 身份验证_类型_id |
---|---|---|---|---|
uuid | varchar | varchar | uuid | |
主键 | 独一无二 | authentication_types 的外键 | ||
7a9d912a-69ab-4615-9058-e1bb1c4e36c5 | 密码 | ... | ... | 0aa4d9a9-e024-4792-bc41-36a4f3528d36 |
用户
id | 已启用 |
---|---|
uuid | 布尔值 |
主键 | |
fc9ca826-63dc-43b8-97b6-2e949ffd8a30 | 真实 |
用户帐户
id | 账户ID | 用户 ID |
---|---|---|
uuid | uuid | uuid |
主键 | 帐户的外键 | 用户的外键 |
bd4b338f-1b5a-4b24-9908-e5cfb4080dd4 | 7a9d912a-69ab-4615-9058-e1bb1c4e36c5 | fc9ca826-63dc-43b8-97b6-2e949ffd8a30 |
验证令牌
id | 过期 | 代币 | 账户 ID |
---|---|---|---|
uuid | 时间戳 | varchar | uuid |
主键 | 独一无二 | 帐户的外键 | |
865a6389-67ea-4e38-a48f-9f4b60ffe816 | ... | ... | 7a9d912a-69ab-4615-9058-e1bb1c4e36c5 |
当新注册发生时,我想做以下事情
这是我经过深思熟虑后提出的问题。获取密码的身份验证类型 ID,并在每一步中运行 CTE 并生成一些 uuid。有没有办法进一步优化?
WITH account_data(id, email, password, authentication_type_id) AS (
VALUES( gen_random_uuid()
,:email
,:password
,(SELECT id
FROM authentication_types
WHERE name = :authenticationTypeName) ) )
,ins1(user_id) AS (
INSERT INTO users(id, enabled)
VALUES( gen_random_uuid()
,true)
RETURNING id AS user_id )
,ins2(account_id) AS (
INSERT INTO accounts (id, email, password, authentication_type_id)
SELECT id
,email
,password
,authentication_type_id
FROM account_data
RETURNING id AS account_id )
,ins3 AS (
INSERT INTO user_accounts (id, account_id, user_id)
VALUES( gen_random_uuid()
,(SELECT account_id
FROM ins2)
,(SELECT user_id
FROM ins1) ) )
INSERT INTO verification_tokens (id, token, account_id)
VALUES( gen_random_uuid()
,:token
,(SELECT account_id
FROM ins2) )
RETURNING (SELECT account_id FROM ins2) AS id
如果有更快的方法来执行上述查询,我将很高兴听到。谢谢您提前的帮助
我假设在此操作之前,后端会进行唯一性检查,检查帐户中是否已存在电子邮件,或者由 API 服务基于 SQLSTATE 适当捕获和处理 ins2 引发的唯一索引违规。响应。以下优化依赖于约束将全部通过的预先知识。
对 DML 进行一些小调整:
WITH account_data(id, email, password, authentication_type_id) AS (
VALUES( gen_random_uuid()
,:email
,:password
,:authentication_type_id --cache these at the level of the CRUD service and submit parameterized
)
), ins1(user_id) AS (
INSERT INTO users(id, enabled)
VALUES( gen_random_uuid(), true )
RETURNING id AS user_id
), ins2(account_id) AS (
INSERT INTO accounts (id, email, password, authentication_type_id)
SELECT id
,email
,password
,:authentication_type_id --parameterized
FROM account_data
RETURNING id AS account_id
), ins3 AS (
INSERT INTO user_accounts (id, account_id, user_id)
SELECT gen_random_uuid()
, account_id
, user_id )
FROM ins1, ins2 --ditch the subqueries, just use the cartesian product of the two preceding always-single records
)
INSERT INTO verification_tokens (id, token, account_id)
SELECT gen_random_uuid()
, :token
, account_id
FROM ins2
RETURNING account_id AS id;
您还可以尝试更改 DDL 以使 PRIMARY KEY 和 FOREIGN KEY 约束DEFERRABLE/INITIALLY DEFERRED,这将导致约束检查和索引更新仅在成功完成所有 4 个 INSERT 后一起运行,而不是在每一个 INSERT 之后运行。这应该会减少您的开销以及高并发实时环境中的死锁风险。
请注意,在数据库上获得类似产品的并发负载之前,您可能不会看到基准性能有任何实质性改进。