CREATE TABLE book ( id serial NOT NULL, name text NOT NULL, author text NOT NULL, year integer NOT NULL, CONSTRAINT pk_book_id PRIMARY KEY ( id ), CONSTRAINT uk_book UNIQUE ( name, author ) ); INSERT INTO book ( name, author, year ) VALUES ( ' β1', ' . .', 2010 ), ( ' β2', ' . .', 2011 ), ( ' β3', ' . .', 2012 ); CREATE OR REPLACE VIEW vw_book AS SELECT b.id, b.name, b.author, b.year, ( b.year >= extract ( year FROM current_date ) - 2 ) AS is_new FROM book b;
-- , UPDATE vw_book SET name = ' β10' WHERE name = ' β1'; -- , is_new UPDATE vw_book SET is_new = false WHERE name = ' β3'; -- , SELECT * FROM vw_book b; -- , SELECT c.column_name, ( is_updatable = 'YES' ) AS is_updatable FROM information_schema.columns c WHERE c.table_name = 'vw_book' ORDER BY ordinal_position;
-- , CREATE OR REPLACE VIEW vw_book_archive AS SELECT b.id, b.name, b.author, b.year FROM vw_book b WHERE b.is_new = false WITH CHECK OPTION; -- , year INSERT INTO vw_book_archive ( name, author, year ) VALUES ( ' β100', ' . .', 2014 ); -- INSERT INTO vw_book_archive ( name, author, year ) VALUES ( ' β100', ' . .', 2010 );
-- DELETE FROM book; INSERT INTO book ( id, name, author, year ) VALUES ( 1, ' β1', ' . .', 2010 ), ( 2, ' β2', ' . .', 2011 ), ( 3, ' β3', ' . .', 2012 ); -- ALTER TABLE book ADD COLUMN promotion_code text; -- UPDATE book SET promotion_code = 'CODE_' || id;
CREATE OR REPLACE VIEW vw_book_list AS SELECT b.* FROM book b WHERE b.name != ' β1'; CREATE OR REPLACE FUNCTION fn_book_promotion_code ( p_name text, p_code text ) RETURNS boolean AS $BODY$ BEGIN RAISE NOTICE 'Book "%" has code "%"', p_name, p_code; RETURN true; END $BODY$ LANGUAGE plpgsql COST 100;
SELECT name, promotion_code FROM vw_book_list l WHERE fn_book_promotion_code ( l.name, l.promotion_code ); -- : -- β2 CODE_2 -- β3 CODE_3 -- : -- NOTICE: Book " β2" has code "CODE_2" -- NOTICE: Book " β3" has code "CODE_3" EXPLAIN ANALYZE SELECT name, promotion_code FROM vw_book_list l WHERE fn_book_promotion_code ( l.name, l.promotion_code ); -- Seq Scan on book b (cost=0.00..1.79 rows=1 width=23) (actual time=0.185..0.217 rows=2 loops=1) Filter: ((name <> ' β1'::text) AND fn_book_promotion_code(name, promotion_code)) Rows Removed by Filter: 1 Planning time: 0.064 ms Execution time: 0.229 ms
CREATE OR REPLACE FUNCTION fn_book_promotion_code ( p_name text, p_code text ) RETURNS boolean AS $BODY$ BEGIN RAISE NOTICE 'Book "%" has code "%"', p_name, p_code; RETURN true; END $BODY$ LANGUAGE plpgsql COST 0.01; SELECT name, promotion_code FROM vw_book_list l WHERE fn_book_promotion_code ( l.name, l.promotion_code ); -- : -- β2 CODE_2 -- β3 CODE_3 -- : -- NOTICE: Book " β1" has code "CODE_1" -- NOTICE: Book " β2" has code "CODE_2" -- NOTICE: Book " β3" has code "CODE_3" EXPLAIN ANALYZE SELECT name, promotion_code FROM vw_book_list l WHERE fn_book_promotion_code ( l.name, l.promotion_code ); -- Seq Scan on book b (cost=0.00..1.04 rows=1 width=23) (actual time=0.215..0.240 rows=2 loops=1) Filter: (fn_book_promotion_code(name, promotion_code) AND (name <> ' β1'::text)) Rows Removed by Filter: 1 Planning time: 0.064 ms Execution time: 0.254 ms
CREATE OR REPLACE VIEW vw_book_list WITH ( security_barrier = true ) AS SELECT b.* FROM book b WHERE b.name != ' β1'; SELECT name, promotion_code FROM vw_book_list l WHERE fn_book_promotion_code ( l.name, l.promotion_code ); -- : -- β2 CODE_2 -- β3 CODE_3 -- : -- NOTICE: Book " β2" has code "CODE_2" -- NOTICE: Book " β3" has code "CODE_3" EXPLAIN ANALYZE SELECT name, promotion_code FROM vw_book_list l WHERE fn_book_promotion_code ( l.name, l.promotion_code ); -- Subquery Scan on l (cost=0.00..1.06 rows=1 width=23) (actual time=0.078..0.106 rows=2 loops=1) Filter: fn_book_promotion_code(l.name, l.promotion_code) -> Seq Scan on book b (cost=0.00..1.04 rows=2 width=52) (actual time=0.009..0.010 rows=2 loops=1) Filter: (name <> ' β1'::text) Rows Removed by Filter: 1 Planning time: 0.069 ms Execution time: 0.122 ms
UPDATE vw_book_list SET promotion_code = 'CODE_555' WHERE name = ' β2';
-- CREATE TABLE author ( id serial NOT NULL, first_name text NOT NULL, last_name text NOT NULL, CONSTRAINT pk_author_id PRIMARY KEY ( id ), CONSTRAINT uk_author_name UNIQUE ( first_name, last_name ) ); -- CREATE TABLE publication ( id serial NOT NULL, author_id integer NOT NULL, name text NOT NULL, CONSTRAINT pk_publication_id PRIMARY KEY ( id ), CONSTRAINT fk_publication_author_id FOREIGN KEY ( author_id ) REFERENCES author ( id ), CONSTRAINT uk_publication_name UNIQUE ( author_id, name ) ); -- INSERT INTO author ( first_name, last_name ) VALUES ( '', '' ); -- id = 1 INSERT INTO author ( first_name, last_name ) VALUES ( '', '' ); -- id = 2 INSERT INTO publication ( author_id, name ) VALUES ( 1, ' β' || generate_series ( 1, 1000000 ) || ')' ); INSERT INTO publication ( author_id, name ) VALUES ( 2, ' ' ), ( 2, ' ' ); β- CREATE MATERIALIZED VIEW mvw_publication AS SELECT p.id, a.first_name || ' ' || a.last_name AS author_name, p.name FROM publication p INNER JOIN author a ON a.id = p.author_id; CREATE UNIQUE INDEX idx_mvw_publication_id ON mvw_ publication ( id ); -- REFRESH MATERIALIZED VIEW CONCURRENTLY mvw_publication; β- ... β- ( ) SELECT * FROM mvw_publication; β- SELECT l.mode FROM pg_locks l INNER JOIN pg_class c ON c.oid = l.relation WHERE .relname = 'mvw_publication';
-- ALTER SYSTEM SET log_min_duration_statement = '1min'; -- ALTER SYSTEM SET log_min_duration_statement TO '2min'; -- ALTER SYSTEM SET log_min_duration_statement TO DEFAULT;
SELECT * FROM unnest ( ARRAY['cat', 'dog', 'mouse'], ARRAY['Tom', 'Jack', 'Lili'] ) WITH ORDINALITY AS t ( cat, dog, mouse ); -- : -- cat Tom 1 -- dog Jack 2 -- mouse Lili 3 -- SELECT *, row_number() OVER () AS i FROM unnest ( ARRAY['cat', 'dog', 'mouse'], ARRAY['Tom', 'Jack', 'Lili'] ) AS t ( cat, dog, mouse );
-- CREATE TABLE salary AS SELECT ( random ( ) * 100 + 2000 )::int AS value FROM generate_series ( 1, 100 ); -- SELECT mode() WITHIN GROUP ( ORDER BY value DESC ) FROM salary; -- , SELECT percentile_disc ( 0.5 ) WITHIN GROUP ( ORDER BY value ) FROM salary; -- , ( ) SELECT percentile_cont ( 0.5 ) WITHIN GROUP ( ORDER BY value ) FROM salary; -- ( 1 / n 1) SELECT s.value, cume_dist ( 2026 ) WITHIN GROUP ( ORDER BY value ) FROM salary s GROUP BY s.value;
-- , 2050 SELECT avg ( s.value ) FILTER ( WHERE s.value >= 2050 ) FROM salary s; -- CASE WHEN β¦ SELECT avg ( CASE WHEN s.value >= 2050 THEN s.value ELSE NULL END ) FROM salary s;
-- IP- CREATE TABLE machine ( ip cidr ); INSERT INTO machine ( ip ) VALUES ( '192.168.1.1'::cidr ), ( '192.168.1.10'::cidr ), ( '192.168.2.11'::cidr ); -- CREATE INDEX idx_machine_ip ON machine USING GiST ( ip inet_ops ); -- 192.168.1.0/24 SELECT * FROM machine WHERE ip && '192.168.1.0/24'::cidr;
EXPLAIN ANALYZE SELECT s.value, count ( * ) FROM salary s GROUP BY s.value HAVING count ( * ) >= 2; -- HashAggregate (cost=2.75..3.60 rows=68 width=4) (actual time=0.045..0.053 rows=26 loops=1) Group Key: value Filter: (count(*) >= 2) Rows Removed by Filter: 42 -> Seq Scan on salary s (cost=0.00..2.00 rows=100 width=4) (actual time=0.007..0.015 rows=100 loops=1) Planning time: 0.042 ms Execution time: 0.082 ms
-- INSERT INTO salary ( value ) SELECT ( random ( ) * 10000 + 1000 )::int AS value FROM generate_series ( 1, 1000000 ); CREATE INDEX idx_salary_value ON salary ( value ); SET work_mem = '64kB'; EXPLAIN ANALYZE SELECT * FROM salary s WHERE s.value BETWEEN 2010 AND 2020; -- Bitmap Heap Scan on salary s (cost=28.83..2739.72 rows=1210 width=4) (actual time=0.370..17.824 rows=1030 loops=1) Recheck Cond: ((value >= 2010) AND (value <= 2020)) Rows Removed by Index Recheck: 96457 Heap Blocks: exact=486 lossy=429 -> Bitmap Index Scan on idx_salary_value (cost=0.00..28.53 rows=1210 width=0) (actual time=0.286..0.286 rows=1030 loops=1) Index Cond: ((value >= 2010) AND (value <= 2020)) Planning time: 0.098 ms Execution time: 17.920 ms SET work_mem = '32MB'; EXPLAIN ANALYZE SELECT * FROM salary s WHERE s.value BETWEEN 2010 AND 2020; -- Bitmap Heap Scan on salary s (cost=28.83..2739.72 rows=1210 width=4) (actual time=0.283..1.214 rows=1030 loops=1) Recheck Cond: ((value >= 2010) AND (value <= 2020)) Heap Blocks: exact=915 -> Bitmap Index Scan on idx_salary_value (cost=0.00..28.53 rows=1210 width=0) (actual time=0.157..0.157 rows=1030 loops=1) Index Cond: ((value >= 2010) AND (value <= 2020)) Planning time: 0.076 ms Execution time: 1.269 ms
CREATE EXTENSION pg_prewarm; CREATE TABLE big AS SELECT array_to_string ( array_agg ( tx ), '' ) || '#' || generate_series ( 1, 10000 ) AS value FROM ( SELECT 'a' || generate_series ( 1, 1000 ) AS x ) t; -- ALTER SYSTEM SET shared_buffers = '256MB';
/etc/init.d/postgresql-9.4 stop sync /etc/init.d/postgresql-9.4 start
-- EXPLAIN ( ANALYZE, BUFFERS ) SELECT * FROM big; -- Seq Scan on big (cost=0.00..76047.00 rows=5000000 width=8) (actual time=0.013..448.978 rows=5000000 loops=1) Buffers: shared read=26047 Planning time: 0.081 ms Execution time: 689.083 ms -- EXPLAIN ( ANALYZE, BUFFERS ) SELECT * FROM big; -- Seq Scan on big (cost=0.00..76047.00 rows=5000000 width=8) (actual time=0.044..449.973 rows=5000000 loops=1) Buffers: shared hit=32 read=26015 Planning time: 0.027 ms Execution time: 692.045 ms -- EXPLAIN ( ANALYZE, BUFFERS ) SELECT * FROM big; -- Seq Scan on big (cost=0.00..76047.00 rows=5000000 width=8) (actual time=0.044..449.973 rows=5000000 loops=1) Buffers: shared hit=32 read=26015 Planning time: 0.027 ms Execution time: 692.045 ms
-- 26047 SELECT pg_prewarm ( 'big' ); EXPLAIN ( ANALYZE, BUFFERS ) SELECT * FROM big; -- Seq Scan on big (cost=0.00..76047.00 rows=5000000 width=8) (actual time=0.007..407.269 rows=5000000 loops=1) Buffers: shared hit=26047 Planning time: 0.129 ms Execution time: 642.834 ms
-- test0 CREATE TABLE city ( country text NOT NULL, name text NOT NULL, CONSTRAINT uk_city_name UNIQUE ( country, name ) ); -- test1 CREATE EXTENSION postgres_fdw; -- CREATE SERVER fdb_server FOREIGN DATA WRAPPER postgres_fdw OPTIONS ( host 'localhost', port '5432', dbname 'test0' ); -- CREATE USER MAPPING FOR PUBLIC SERVER fdb_server OPTIONS ( password 'pwd' ); -- CREATE FOREIGN TABLE fdb_city ( country text, name text ) SERVER fdb_server OPTIONS ( table_name 'city' );
-- test1 CREATE OR REPLACE FUNCTION tfn_city_change ( ) RETURNS trigger AS $BODY$ BEGIN IF ( NEW.name = 'N/A' ) THEN RAISE EXCEPTION 'City with name "N/A" not allowed'; END IF; RETURN NEW; END $BODY$ LANGUAGE plpgsql VOLATILE; CREATE TRIGGER tr_city_change BEFORE INSERT ON fdb_city FOR EACH ROW EXECUTE PROCEDURE tfn_city_change ( ); -- INSERT INTO fdb_city ( country, name ) VALUES ( 'USA', 'New York' ); -- INSERT INTO fdb_city ( country, name ) VALUES ( 'USA', 'N/A' );
-- test0 -- INSERT INTO city ( country, name ) VALUES ( 'Italy', 'N/A' );
JSON type | PostgreSQL type |
---|---|
string | text |
number | numeric |
boolean | boolean |
-- CREATE TABLE book ( id serial NOT NULL, name text NOT NULL, params jsonb NOT NULL DEFAULT '{}' ); -- INSERT INTO book ( name, params ) SELECT ' #' || tx, ( '{ "pages": ' || 500 + ( tx % 500 ) || CASE tx % 1000 WHEN 0 THEN ', "gold_edition": true' ELSE '' END || ' }' )::jsonb FROM ( SELECT generate_series ( 1, 1000000 ) x ) t; -- "" SELECT count ( * ) FROM book WHERE params @> '{ "gold_edition": true }'::jsonb; -- SELECT count ( * ) > 0 FROM book WHERE name = ' #1' AND params ? 'pages'; -- SELECT params -> 'pages' FROM book WHERE name = ' #11'; -- "pages" SELECT jsonb_typeof ( params -> 'pages' ) FROM book WHERE name = ' #11'; -- CREATE INDEX idx_book_params ON book USING gin ( params jsonb_path_ops );
Source: https://habr.com/ru/post/234909/
All Articles