sqb*_*ell 8 postgresql postgresql-9.4
在我们的 PostgreSQL 9.4.4 数据库中,我们有一个每天接收大约 60 万条新记录的表。每天,每晚,我们都会从表中执行一些 ETL 导出。如果在导出之前没有分析过,真的很慢。如果我们运行ANALYZE
,速度会更快,因为规划器使用具有我们查询的字段的多列索引。解决慢查询问题的首选方法是什么?我看到三个选项:
ANALYZE
在出口之前,第二个选项要求我们指定每个表的自动清理/分析设置,因为默认设置不适用于大表。即使我们正确设置了它,也有一些边缘情况,当它仍然会引起麻烦时。例如:
autovacuum_analyze_scale_factor = 0.1
Run Code Online (Sandbox Code Playgroud)
现在是默认值 - 所以如果我们的表有大约 2500 万条记录,它会在 250 万条记录后分析,这对我们来说不够频繁(我们每天有大约 60 万笔新交易)。但是,如果我们将其设置为 0.02(约 500k 条记录),则可能会发生这样的情况,对于有许多事务(例如 900k)的一天,我们将在 500k 之后运行 ANALYZE,但 400k 将保持未分析状态,这将影响查询性能。
表结构:
Table "public.bet_transactions"
Column | Type | Modifiers
----------------------------+-----------------------------+---------------------------------------------------------------
id | integer | not null default nextval('bet_transactions_id_seq'::regclass)
account_id | integer | not null
amount_cents | integer | not null default 0
money_amount_cents | integer | not null default 0
bonus_amount_cents | integer | not null default 0
wager_amount_cents | integer | not null default 0
currency | character varying(3) | not null default 'EUR'::character varying
total_balance_before_cents | integer | not null default 0
total_balance_after_cents | integer | not null default 0
money_balance_before_cents | integer | not null default 0
money_balance_after_cents | integer | not null default 0
bonus_balance_before_cents | integer | not null default 0
bonus_balance_after_cents | integer | not null default 0
wager_balance_before_cents | integer | not null default 0
wager_balance_after_cents | integer | not null default 0
status | character varying(255) | not null
reason | character varying(255) |
provider | character varying(255) | not null
external_unique_id | character varying(255) |
external_group_id | character varying(255) |
external_reason | character varying(255) |
external_data | hstore | not null default ''::hstore
search_vector | tsvector |
created_at | timestamp without time zone |
updated_at | timestamp without time zone |
exchange_rate | double precision | not null default 1
original_currency | character varying(3) | not null default 'EUR'::character varying
original_amount_cents | integer | not null default 0
game_id | integer | not null
external_game_id | character varying(255) |
big_win | boolean |
contribution_factor | integer |
Indexes:
"bet_transactions_pkey" PRIMARY KEY, btree (id)
"ux_bet_transactions_provider_external_unique_id" UNIQUE, btree (account_id, provider, external_unique_id) WHERE external_unique_id IS NOT NULL
"ix_bet_transactions_account_game_status_and_date" btree (account_id, game_id, created_at) WHERE status::text = 'accepted'::text AND created_at >= '2015-01-01 00:00:00'::timestamp without time zone
"ix_bet_transactions_account_id_external_group_id" btree (account_id, external_group_id)
"ix_bet_transactions_date_created_at" btree (date(created_at))
Inherits: game_transactions
Run Code Online (Sandbox Code Playgroud)
示例查询(批处理):
SELECT "bet_transactions".*, "bet_transactions".tableoid::regclass::text as "table_name" FROM "bet_transactions" INNER JOIN "accounts" ON "accounts"."id" = "bet_transactions"."account_id" INNER JOIN "players" ON "players"."id" = "accounts"."player_id" WHERE (bet_transactions.tableoid::regclass::text = 'bet_transactions'::text) AND ("bet_transactions"."created_at" >= '2015-07-02 22:00:00.000000' AND "bet_transactions"."created_at" < '2015-07-03 22:00:00.000000') AND "bet_transactions"."status" = 'accepted' ORDER BY "bet_transactions"."created_at" ASC LIMIT 5000 OFFSET 0
Run Code Online (Sandbox Code Playgroud)
你看到任何替代品吗?这种情况通常如何处理?
编辑:添加了表结构和示例查询。
小智 6
正如上面评论中已经指出的,隐藏了一些细节。我从你的问题中了解到,查询计划在ANALYZE
. 这可能表明查询规划器使用的统计数据没有反映数据的真实分布。
ANALYZE
无论如何,只需要一个样本 - 它不会调查整个表。这意味着autovacuum_analyze_threshold
只有当新行会显着改变整个表中的分布时,调整对我来说才有意义。这取决于您的用例。
在我看来,调整样本的大小似乎更重要ANALYE
。您可以通过设置统计目标来影响表的样本大小(不幸的是问题中没有提到)。这篇博文展示了如何statistics target
影响ANALYZE
.
归档时间: |
|
查看次数: |
3161 次 |
最近记录: |