面临奇怪的行为EXISTS(也适用于NOT EXISTS)生成不同的执行计划
WHERE EXISTS(...)
EXPLAIN ANALYZE
SELECT * FROM books
WHERE EXISTS (SELECT 1 FROM authors WHERE id = books.author_id AND name LIKE 'asd%');
| QUERY PLAN |
| -------------------------------------------------------------------------------------------------------------- |
| Hash Join (cost=218.01..454.43 rows=56 width=40) (actual time=0.975..0.975 rows=0 loops=1) |
| Hash Cond: (books.author_id = authors.id) |
| -> Seq Scan on books (cost=0.00..206.80 rows=11280 width=40) (actual time=0.010..0.010 rows=1 loops=1) |
| -> Hash (cost=217.35..217.35 rows=53 width=4) (actual time=0.943..0.943 rows=0 loops=1) |
| Buckets: …Run Code Online (Sandbox Code Playgroud) 我正在尝试执行一项常见任务,从表中删除重复项,目的是添加唯一约束。
CREATE TABLE IF NOT EXISTS item_identifier (
pk BIGSERIAL PRIMARY KEY,
prefix INTEGER NOT NULL,
suffix VARCHAR(1024) NOT NULL
);
CREATE INDEX temp_prefix_suffix_idx ON item_identifier (prefix, suffix);
Run Code Online (Sandbox Code Playgroud)
我想使用常见查询删除重复项,该查询可以在本网站的许多答案中找到。我认为重复率大约为 1%,因此没有太多需要删除的内容。
提供索引纯粹是为了帮助重复数据删除,稍后将被删除。不过,如您所见,PostgreSQL 甚至没有使用它!
有 2,759,559,168 行。索引temp_prefix_suffix_idx本身约为 100 GB。花CREATE INDEX了 12 个小时所以我不指望DELETE会很快。但根据 10% 的样本集,我推断需要 20 小时,而实际上已经花了 40 小时。对于我的示例方法来说,它可能仍在误差范围内,但我担心由于它不使用索引,这将花费指数时间。
这EXPLAIN有Seq Scan on item_identifier a和Seq Scan on item_identifier b。
EXPLAIN DELETE FROM item_identifier a
WHERE EXISTS
(SELECT FROM item_identifier b
WHERE a.prefix …Run Code Online (Sandbox Code Playgroud) 当我分配一个变量时
result := title || '', by '' || author;
Run Code Online (Sandbox Code Playgroud)
运行该函数需要更多时间(大约 15 秒)。
但是,当我分配变量时
result = title || '', by '' || author;
Run Code Online (Sandbox Code Playgroud)
只需要133ms。
为什么第一个场景需要更多时间?这背后的原因是什么?
下面给出了完整的功能。
CREATE OR REPLACE FUNCTION myschema.fn_get_res_no(reservation_no character varying)
RETURNS character varying AS
$BODY$
DECLARE
emd_status_firstcall varchar(2);
emd_status_secondcall varchar(2);
emd_status varchar(6);
BEGIN
SELECT firstwscomplete, secondwscomplete
INTO emd_status_firstcall, emd_status_secondcall
FROM myschema.mytable
WHERE respkgconfirmid = reservation_no;
emd_status = emd_status_firstcall || ', ' || emd_status_secondcall;
RETURN emd_status ;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Run Code Online (Sandbox Code Playgroud) 在位串列上创建索引的最佳方法是什么?假设我有一个 type 列,bit(4)我想搜索所有设置了特定位的条目。所以如果我有条目:
bitfield | ...
--------------
1001
1010
0110
0010
0000
Run Code Online (Sandbox Code Playgroud)
如果我试图搜索所有0010设置的条目,我可以轻松地做到这一点。但是我可以使用索引来优化搜索吗?
我有一个包含日期时间字段start和end. 我有一个(开始,结束)项目列表。我需要检查列表中的哪些项目与表中的数据重叠。当前查询如下所示:
select br.duration from booking, (
select tstzrange('2016-09-06 03:45:00+00', '2016-09-06 14:45:00+00') as duration
union select tstzrange('2016-09-06 14:45:00+00', '2016-09-06 15:45:00+00') as duration
-- other items from my list
) as br
where tstzrange(start, end) && br.duration
Run Code Online (Sandbox Code Playgroud)
有没有其他方法可以做到?如果我在表中有数百万行并将它们与列表中的数百个项目进行比较,您认为它会起作用吗?
postgresql performance gist-index range-types postgresql-performance
假设一个充满产品的数据库。一个产品可以恰好属于 1 个集合并且由用户创建。数据库的粗略规模:
我正在尝试检索用户拥有的产品+集合的数量,以及每个集合中的产品数量(该信息应该在所有 x 天生成并在 ElasticSearch 中编入索引)。
对于用户查询,我目前正在做这样的事情:
SELECT
users.*,
(SELECT
count(*)
FROM
products product
WHERE
product.user_id = user.id
) AS product_count,
(SELECT
count(*)
FROM
collections collection
WHERE
collection.user_id = user.id
) AS collection_count
FROM
users user
Run Code Online (Sandbox Code Playgroud)
所有 *_id 字段都已编入索引。使用解释(分析,详细)(删除敏感信息):
Limit (cost=0.00..156500.97 rows=100 width=41) (actual time=0.064..28345.363 rows=100 loops=1)
Output: (...), ((SubPlan 1)), ((SubPlan 2))
-> Seq Scan on public.users user (cost=0.00..14549429167.11 rows=9296702 width=41) (actual time=0.064..28345.241 rows=100 loops=1)
Output: (...), (SubPlan 1), (SubPlan 2)
SubPlan 1 …Run Code Online (Sandbox Code Playgroud) 谷歌搜索后,很明显你不能从函数运行真空:
Postgres 邮件 - plpgsql 函数中的真空行为
由于内存管理限制,您无法从函数内部运行 VACUUM。在当前来源中有一个错误检查以防止您尝试。
Stackoverflow - 无法从函数或多命令字符串执行 VACUUM
加载数据后,我想对受影响的表进行“真空分析”,既要从已删除的记录中恢复空间,又要准确反映新内容。[...] 当我运行这个时,我得到:
ERROR: VACUUM cannot be executed from a function or multi-command string
但是我真的需要在运行某个函数时“自动”运行vacuum:这个函数更新了很多记录(如果不是全部),所以死行的数量增加得非常快,其他查询性能下降很多。问题是该函数是从另一个程序调用的。任何最佳实践?我应该在函数执行后手动将真空语句添加到一段单独的代码中,就像
sql = SELECT my_function()
<program.execute(sql)>
sql = VACUUM [FULL | ANALYZE] my_updated_table
<program.execute(sql)>
我将数百万行插入 PostgreSQL 9.5 数据库并观察到内存使用量的持续增长。由于表不是那么大,并且执行的操作(插入触发 Pl/Python 函数)不应该那么昂贵,我想知道为什么会发生这种情况。
目前 PostgreSQL 使用了大约 50 GB 的总可用空间 60 GB。我想了解 PostgreSQL 如何使用这 50 GB,尤其是因为我担心该进程会耗尽内存。
[更新] 今晚 PostgreSQL 内存不足,被操作系统杀死。
$ pg_top
last pid: 13535; load avg: 1.26, 1.41, 1.42; up 2+02:57:11 19:29:26
3 processes: 1 running, 2 sleeping
CPU states: 12.4% user, 0.0% nice, 0.1% system, 87.4% idle, 0.0% iowait
Memory: 63G used, 319M free, 192M buffers, 28G cached
DB activity: 2 tps, 0 rollbs/s, 0 buffer r/s, 100 hit%, 42 row r/s, 0 row w/s
DB …Run Code Online (Sandbox Code Playgroud) 有这样的问题 - 超过 2000 万行的表。
当我使用默认值添加新列时 - postgresql 锁定表超过 40 分钟,因此我的应用程序此时停止工作。
所以代替
ALTER TABLE "test" ADD COLUMN "field" boolean DEFAULT True NOT NULL;
Run Code Online (Sandbox Code Playgroud)
我愿意
ALTER TABLE "test" ADD COLUMN "field" boolean NULL;
ALTER TABLE "test" ALTER COLUMN "field" SET DEFAULT true;
Run Code Online (Sandbox Code Playgroud)
之后每个新行默认为 true,所以现在我需要更新 2000 万个当前行。我分批更新它们:
WITH cte AS (
SELECT id as pk
FROM "test"
WHERE "field" is null
LIMIT 10000
)
UPDATE "test" table_
SET "field" = true
FROM cte
WHERE table_.id = cte.pk
Run Code Online (Sandbox Code Playgroud)
之后我做
ALTER TABLE "test" ALTER …Run Code Online (Sandbox Code Playgroud) 我知道在表上执行 VACUUM FULL 将释放磁盘空间并将其返回给操作系统。
有几次我的操作系统(Windows)警告我它的磁盘空间不足。我的反应是迅速关闭我所能做的一切,并在其中一个更活跃的表上运行 VACUUM FULL。
我注意到 VACUUM FULL 似乎需要至少几百 MB 的空闲空间才能实际工作。如果我在只有 50 MB 的磁盘空间时尝试在 1GB 的表上执行 VACCUM FULL,那么这很快就会消失,我的计算机很快就会停止,而 VACUUM FULL 将无法工作。
当我知道有未使用的空间可用但没有足够的空间来运行 VACUUM 时,如何释放 POSTGRES 数据库中的操作系统空间?
(我知道正确的答案是——“不要傻到一开始就让它发生”,但 sh1t 偶尔会发生!)
postgresql ×10
performance ×8
exists ×2
index ×2
alter-table ×1
count ×1
gist-index ×1
memory ×1
plpgsql ×1
range-types ×1
vacuum ×1