问题实际上是关于 sql 查询的优化。假设我们有这样定义的表。
CREATE TYPE record_type AS ENUM (
'TRANSFER',
'TRADE',
'VOUCHER'
);
CREATE TYPE record_status AS ENUM (
'NEW',
'VALIDATED',
'EXPIRED'
);
CREATE TABLE good_records (
id uuid PRIMARY KEY,
user_id uuid NOT NULL,
type record_type NOT NULL,
status record_status NOT NULL,
amount numeric(36,18) NOT NULL DEFAULT 0,
expired_at timestamp WITH TIME ZONE NOT NULL,
notification_sent boolean DEFAULT false,
);
Run Code Online (Sandbox Code Playgroud)
我想每 10 分钟运行一次过期检查,即我会运行SELECT * FROM good_records
where record_status = 'NEW' and notification_sent = false(和SELECT * FROM …
我有一个users包含字段id和 的表email。id是主键并且email也被索引。
database> \d users
+-----------------------------+-----------------------------+-----------------------------------------------------+
| Column | Type | Modifiers |
|-----------------------------+-----------------------------+-----------------------------------------------------|
| id | integer | not null default nextval('users_id_seq'::regclass) |
| email | character varying | |
+-----------------------------+-----------------------------+-----------------------------------------------------+
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
"index_users_on_email" UNIQUE, btree (email)
Run Code Online (Sandbox Code Playgroud)
如果我在子查询中使用子句查询表,distinct on (email)我会得到显着的性能损失。
database> \d users
+-----------------------------+-----------------------------+-----------------------------------------------------+
| Column | Type | Modifiers |
|-----------------------------+-----------------------------+-----------------------------------------------------|
| id | integer | not null default nextval('users_id_seq'::regclass) |
| …Run Code Online (Sandbox Code Playgroud) postgresql performance greatest-n-per-group distinct-on postgresql-performance
我正在使用 NEAR 协议的公共 Postgres 数据库:https://github.com/near/near-indexer-for-explorer#shared-public-access
postgres://public_readonly:nearprotocol@mainnet.db.explorer.indexer.near.dev/mainnet_explorer
SELECT "public"."receipts"."receipt_id",
"public"."receipts"."included_in_block_hash",
"public"."receipts"."included_in_chunk_hash",
"public"."receipts"."index_in_chunk",
"public"."receipts"."included_in_block_timestamp",
"public"."receipts"."predecessor_account_id",
"public"."receipts"."receiver_account_id",
"public"."receipts"."receipt_kind",
"public"."receipts"."originated_from_transaction_hash"
FROM "public"."receipts"
WHERE ("public"."receipts"."receipt_id") IN
(SELECT "t0"."receipt_id"
FROM "public"."receipts" AS "t0"
INNER JOIN "public"."action_receipts" AS "j0" ON ("j0"."receipt_id") = ("t0"."receipt_id")
WHERE ("j0"."signer_account_id" = 'ryancwalsh.near'
AND "t0"."receipt_id" IS NOT NULL))
ORDER BY "public"."receipts"."included_in_block_timestamp" DESC
LIMIT 1
OFFSET 0
Run Code Online (Sandbox Code Playgroud)
总是会导致:
ERROR: canceling statement due to statement timeout
SQL state: 57014
Run Code Online (Sandbox Code Playgroud)
但如果我将其更改为 LIMIT 2,则查询运行时间不到 1 秒。
怎么会是这样呢?这是否意味着数据库没有设置好?或者我做错了什么?
PS 这里的查询是通过 Prisma 生成的。findFirst总是超时,所以我想我可能需要将其更改findMany为解决方法。
SELECT DISTINCT options.id, options.foo_option_id, options.description
FROM vehicles
INNER JOIN vehicle_options ON vehicle_options.vehicle_id = vehicles.id
INNER JOIN options ON options.id = vehicle_options.option_id
INNER JOIN discounted_vehicles ON vehicles.id = discounted_vehicles.vehicle_id
WHERE discounted_vehicles.discount_id = 4;
Run Code Online (Sandbox Code Playgroud)
上面的查询返回 2067 行,它在 1.7 秒内在本地运行。我想知道它是否尽可能快,或者我是否可以以某种方式进一步调整它,因为这个数据集会随着时间的推移而快速增长。
我在速度不变的情况下尝试过的事情:
1 - 更改连接顺序,从最小的表连接到最大的表。
2 - 向discounted_vehicles.discount_id 添加索引。
这是将 SUM group by 添加到 COUNT DISTINCT 查询中的后续优化(尽管进行了一些优化和联接简化)。
我想知道是否可以优化以下需要完成的PostgreSQL 13.1查询130322.2ms。通常,如果只有一个JOIN LATERAL存在,它会在几毫秒内完成。
我最迷失的是,每个子查询JOIN LATERAL都有一个ON基于其自己的子查询分数的条件,我如何优化查询,可能减少子查询的数量JOIN LATERAL,但仍然得到相同的结果。
从我看来,当条件添加到代替OR中的某些 WHERE时,它似乎会变慢。看:JOIN LATERALAND
SELECT count(*)
FROM subscriptions q
JOIN LATERAL (
SELECT
SUM(ts.score) AS sum_score
FROM
quiz_answers qa
JOIN answers a ON a.id = qa.answer_id
JOIN tag_scores ts ON ts.answer_id = a.id
WHERE
qa.quiz_id = q.quiz_id
AND ts.tag_id = 21
) AS q62958 ON q62958.sum_score <= 1
JOIN LATERAL …Run Code Online (Sandbox Code Playgroud)