수십억 개의 행을 가진 Postgres 테이블이 있으며 기계 학습 응용 프로그램의 경우 열차 및 테스트 세트로 나누어야합니다.포스트 그램의 연속적인 행 부분 집합을 효율적으로 표시하십시오.
나는 테스트 행이 자신의 id
열을 기준으로 대부분이 연속되고 싶어요, 그래서 무작위로 1,000 연속 행 각각의 여러 덩어리를 선택하고 테스트 행로 표시하고 싶습니다.
UPDATE table SET test=true WHERE id BETWEEN 100000 AND 101000;
매우 효율적이며, 사용자가 예상하는대로 인덱스 스캔을 사용 : 내가 그렇게 임의 1,000 연속 행을 선택하여 id
컬럼에 인덱스가 빠르고입니다. 불행하게도 최대한 빨리 초기 id
가 무작위로 생성 할 수 있도록로 즉
WITH off AS (SELECT ROUND(random()*maxId))
UPDATE table SET test=true
WHERE id BETWEEN (SELECT * FROM off LIMIT 1)
AND (SELECT * FROM off LIMIT 1)+1000;
쿼리 플래너 지금은 전체 테이블 스캔 (매우 느리게)를 수행하기로 결정합니다.
물론이 작업을 한 번만 수행하면 수동으로 임의의 행을 생성 할 수 있습니다. 문제가 없습니다. 그러나 결국에는 아래처럼 테스트와 열차로 자동으로 나누는 함수가 필요합니다 :
CREATE OR REPLACE FUNCTION test_train_divide(chunkSize integer, proportion real)
RETURNS BOOLEAN
AS $$
DECLARE
maxId INTEGER := (SELECT MAX(id) FROM table);
BEGIN
FOR i IN 1 .. round(maxId*proportion/chunkSize) LOOP
RAISE NOTICE 'Update call %', i;
WITH off AS (SELECT ROUND(random()*maxId))
UPDATE table SET test=true
WHERE id BETWEEN (SELECT * FROM off LIMIT 1)
AND (SELECT * FROM off LIMIT 1)+chunkSize;
END LOOP;
return true;
END;
$$ LANGUAGE plpgsql;
SELECT test_train_divide(1000,0.01);
이 작동하지만 아주 천천히! 어떤 포인터? 여기에 업데이트
는
tbl "public.tbl”
Column | Type | Modifiers
-----------+---------+-----------
subid | integer |
id | bigint |
wordid | integer |
capid | integer |
test | boolean |
Indexes:
“tbl_id_idx" btree (id)
그리고 여기가 (인덱스를 사용하는) 두 개의 서로 다른 쿼리 계획, 하나 개의 좋은 일 나쁜있는 스키마입니다 :
will=# EXPLAIN UPDATE tbl SET test=true WHERE id BETWEEN 1000000 AND 1001000;
QUERY PLAN
---------------------------------------------------------------------------------------------------
Update on tbl (cost=0.57..790.45 rows=1079 width=38)
-> Index Scan using tbl_id_idx on tbl (cost=0.57..790.45 rows=1079 width=38)
Index Cond: ((id >= 1000000) AND (id <= 1001000))
(3 rows)
will=# EXPLAIN WITH start AS (SELECT round(random()*max(id)) FROM tbl) UPDATE tbl c SET test=true WHERE c.id BETWEEN (SELECT * FROM start LIMIT 1) AND (SELECT * FROM start LIMIT 1)+1000;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
Update on tbl c (cost=0.65..14932243.97 rows=1459961 width=38)
CTE start
-> Result (cost=0.59..0.61 rows=1 width=0)
InitPlan 1 (returns $0)
-> Limit (cost=0.57..0.59 rows=1 width=8)
-> Index Only Scan Backward using tbl_id_idx on tbl (cost=0.57..5846291.90 rows=288468819 width=8)
Index Cond: (id IS NOT NULL)
InitPlan 3 (returns $2)
-> Limit (cost=0.00..0.02 rows=1 width=8)
-> CTE Scan on start (cost=0.00..0.02 rows=1 width=8)
InitPlan 4 (returns $3)
-> Limit (cost=0.00..0.02 rows=1 width=8)
-> CTE Scan on start start_1 (cost=0.00..0.02 rows=1 width=8)
-> Seq Scan on tbl c (cost=0.00..14932243.32 rows=1459961 width=38)
Filter: (((id)::double precision >= $2) AND ((id)::double precision <= ($3 + 1000::double precision)))
(15 rows)
Time: 2.649 ms
비슷한 질문 성능 질문 –
"효율적으로 임의의 행을 선택,"우리는 포스트 그레스의 버전이 필요합니다. 그리고 기본 테이블 정의는 항상 유용하다 ('CREATE TABLE' 문 또는 psql의'\ d tbl'). –
좋아요. Postgres 9.3에 대한 정보를 더 제공해 줬습니다. 이제 테이블 정의가 – wxs