Приховані можливості PostgreSQL [закрито]


80

Я здивований, що це ще не розміщено. Будь-які цікаві трюки, про які ви знаєте у Postgres? Незрозумілі параметри конфігурації та прийоми масштабування / перформансу особливо вітаються.

Я впевнений, що ми можемо обіграти 9 коментарів до відповідного потоку MySQL :)

Відповіді:


76

Оскільки postgres набагато розумніший, ніж MySQL, існує не так багато "хитрощів", ​​про які можна звітувати ;-)

У посібнику є кілька приємних підказок щодо ефективності .

Майте на увазі ще кілька речей, пов’язаних із продуктивністю:

  • Переконайтеся, що автовакуум увімкнено
  • Переконайтеся, що ви пройшли ваш postgres.conf (ефективний розмір кешу, спільні буфери, робоча пам’ять ... безліч варіантів, які можна налаштувати).
  • Використовуйте pgpool або pgbouncer, щоб звести "реальні" з'єднання з базою даних до мінімуму
  • Дізнайтеся, як працює EXPLAIN та EXPLAIN ANALYZE. Навчіться читати результати.
  • CLUSTER сортує дані на диску відповідно до індексу. Може суттєво покращити роботу великих (переважно) таблиць лише для читання. Кластеризація - це одноразова операція: коли таблиця згодом оновлюється, зміни не кластеризуються.

Ось кілька речей, які я знайшов корисними, і які не пов'язані з конфігурацією чи продуктивністю як такі.

Щоб побачити, що зараз відбувається:

select * from pg_stat_activity;

Пошук різних функцій:

select * from pg_proc WHERE proname ~* '^pg_.*'

Знайти розмір бази даних:

select pg_database_size('postgres');
select pg_size_pretty(pg_database_size('postgres'));

Знайти розмір усіх баз даних:

select datname, pg_size_pretty(pg_database_size(datname)) as size
  from pg_database;

Знайти розмір таблиць та індексів:

select pg_size_pretty(pg_relation_size('public.customer'));

Або, щоб перерахувати всі таблиці та індекси (мабуть, простіше це переглянути):

select schemaname, relname,
    pg_size_pretty(pg_relation_size(schemaname || '.' || relname)) as size
  from (select schemaname, relname, 'table' as type
          from pg_stat_user_tables
        union all
        select schemaname, relname, 'index' as type
          from pg_stat_user_indexes) x;

О, і ви можете вкладати транзакції, відмовляти часткові транзакції ++

test=# begin;
BEGIN
test=# select count(*) from customer where name='test';
 count 
-------
     0
(1 row)
test=# insert into customer (name) values ('test');
INSERT 0 1
test=# savepoint foo;
SAVEPOINT
test=# update customer set name='john';
UPDATE 3
test=# rollback to savepoint foo;
ROLLBACK
test=# commit;
COMMIT
test=# select count(*) from customer where name='test';
 count 
-------
     1
(1 row)

Дякую. EDIT: Додана інформація про CLUSTER.
tommym

Показ розміру бази даних є однією з особливостей "\ l" у 8.4 бета-версії psql, я помітив. До того часу, я думаю, 8.3 має функцію pg_size_pretty (), щоб визначити розмір у байтах.
araqnid

Дякуємо за підказку! Не знав pg_size_pretty. Я оновив свою відповідь, щоб включити її.
tommym

3
replace (відповідь, 'per say', 'per se')
asjo

23

Простий трюк , щоб виконати PostgreSQL набагато краще (крім установки і використання власних індексів, звичайно) просто дати йому більше оперативної пам'яті для роботи з (якщо ви ще не зробили цього). У більшості установок за замовчуванням значення для shared_buffers занадто низьке (на мій погляд). Ви можете встановити

shared_buffers

у postgresql.conf. Поділіть це число на 128, щоб отримати приблизний обсяг пам'яті (у МБ), який можуть вимагати postgres. Якщо ви цього достатньо, це змусить postgresql літати. Не забудьте перезапустити postgresql.

У системах Linux, коли postgresql не запускатиметься знову, ви, мабуть, досягли межі kernel.shmmax. Встановіть його вище за допомогою

sysctl -w kernel.shmmax=xxxx

Щоб це зберігалося між завантаженнями, додайте запис kernel.shmmax до /etc/sysctl.conf.

Цілу купу фокусів Postgresql можна знайти тут :


17

Postgres має надзвичайно потужний пристрій обробки дат та часу завдяки підтримці INTERVAL.

Наприклад:

select NOW(), NOW() + '1 hour';
              now              |           ?column?            
-------------------------------+-------------------------------
 2009-04-18 01:37:49.116614+00 | 2009-04-18 02:37:49.116614+00
(1 row)



select current_date ,(current_date +  interval '1 year')::date;
    date             |  date            
---------------------+----------------
 2014-10-17          | 2015-10-17
(1 row)

Ви можете передати багато рядків типу INTERVAL.


15

КОПІЮВАННЯ

Я почну. Кожного разу, коли я переходжу на Postgres з SQLite, я зазвичай маю кілька справді великих наборів даних. Головне - завантажувати ваші таблиці з COPY FROM, а не робити INSERTS. Дивіться документацію:

http://www.postgresql.org/docs/8.1/static/sql-copy.html

Наступний приклад копіює таблицю клієнту, використовуючи вертикальну смужку (|) як роздільник поля:

COPY country TO STDOUT WITH DELIMITER '|';

Щоб скопіювати дані з файлу в таблицю країн:

COPY country FROM '/usr1/proj/bray/sql/country_data';

Дивіться також тут: Швидші об’ємні вставки в sqlite3?


2
Це також стає в нагоді для імпорту csv.
ChristopheD

В останніх випусках (принаймні 8.3, можливо раніше), якщо СТВОРИТИ або ОБРУБИТИ таблицю, яку ви заповнюєте в тій самій транзакції, що і КОПІЮВАННЯ, вона не торкнеться журналу WAL, і ви отримаєте ще більш високу продуктивність. postgresql.org/docs/8.3/static/populate.html
ДЕРЕВО

12
  • На сьогоднішній день улюбленим є generate_series: нарешті, чистий спосіб створення фіктивних наборів рядків.
  • Можливість використовувати співвідношене значення в LIMITреченні підзапиту:

    SELECT  (
            SELECT  exp_word
            FROM    mytable
            OFFSET id
            LIMIT 1
            )
    FROM    othertable
    
  • Доступність використання кількох параметрів у спеціальних агрегатах (не охоплюється документацією): див . Приклад у статті в моєму блозі .

1
+1, create_series () - це саме те, що потрібно для багатьох речей (наприклад, коли вам потрібна "фіктивна таблиця"). Другий фрагмент теж виглядає інтригуюче.
j_random_hacker

9

Одне з речей, яке мені дуже подобається у Postgres, це деякі типи даних, що підтримуються у стовпцях. Наприклад, існують типи стовпців, створені для зберігання мережевих адрес і масивів . Відповідні функції ( Мережеві адреси / масиви ) для цих типів стовпців дозволяють робити багато складних операцій усередині запитів, які вам доведеться зробити, обробляючи результати за допомогою коду в MySQL або інших механізмах баз даних.


2
І ви можете легко створити власні типи, якщо стандартні вам не підходять!
bortzmeyer

8

Після того, як ви їх дізнаєтесь, масиви справді круті. Скажімо, ви хотіли б зберігати деякі гіперпосилання між сторінками. Ви можете почати з роздумів про створення таблиці приблизно так:

CREATE TABLE hyper.links (
     tail INT4,
     head INT4
);

Якщо вам потрібно було проіндексувати стовпчик хвоста , і у вас було, скажімо, 200 000 000 посилань-рядків (як дасть вам Вікіпедія), ви опинилися б із величезною таблицею та величезним показником.

Однак з PostgreSQL ви можете використовувати цей формат таблиці:

CREATE TABLE hyper.links (
     tail INT4,
     head INT4[],
     PRIMARY KEY(tail)
);

Щоб отримати всі заголовки для посилання, ви можете надіслати таку команду (unnest () є стандартною з 8.4):

SELECT unnest(head) FROM hyper.links WHERE tail = $1;

Цей запит напрочуд швидкий, якщо його порівняти з першим варіантом (unnest () швидкий, а індекс набагато менший). Крім того, таблиця та індекс займуть набагато менше оперативної пам’яті та HD-місця, особливо коли ваші масиви настільки довгі, що стискаються до таблиці тостів. Масиви дійсно потужні.

Примітка: хоча unnest () буде генерувати рядки з масиву, array_agg () буде агрегувати рядки в масив.


6

Матеріалізовані подання досить прості в налаштуванні:

CREATE VIEW my_view AS SELECT id, AVG(my_col) FROM my_table GROUP BY id;
CREATE TABLE my_matview AS SELECT * FROM my_view;

Це створює нову таблицю my_matview зі стовпцями та значеннями my_view. Потім можна настроїти тригери або скрипт cron, щоб підтримувати дані в актуальному стані, або якщо ви ліниві:

TRUNCATE my_matview;
INSERT INTO my_matview SELECT * FROM my_view;

6
  • Наслідування..вплив Множинне успадкування (як у "успадкуванні" батьків-дочірніх), а не у спадкуванні відношення 1-до-1, яке багато веб-фреймворків реалізують при роботі з postgres).

  • PostGIS (просторове розширення), чудовий додаток, який пропонує повний набір геометричних функцій та зберігає координати. Широко використовується у багатьох відкритих джерелах гео-бібліотек (наприклад, OpenLayers, MapServer, Mapnik тощо) і, безумовно, набагато кращий, ніж просторові розширення MySQL.

  • Процедури написання різними мовами, наприклад, C, Python, Perl тощо (полегшує вам кодування життя, якщо ви розробник, а не адміністратор DB).

    Також усі процедури можуть зберігатися зовні (як модулі) і можуть бути викликані або імпортовані під час виконання за вказаними аргументами. Таким чином ви можете легко керувати кодом та налагоджувати код.

  • Величезний і повний каталог усіх об’єктів, реалізованих у вашій базі даних (тобто таблиць, обмежень, індексів тощо).

    Я завжди вважаю надзвичайно корисним запустити кілька запитів і отримати всю метаінформацію, наприклад, імена обмежень та поля, на яких вони були реалізовані, імена індексів тощо.

    Для мене все стає надзвичайно зручним, коли мені доводиться завантажувати нові дані або робити масові оновлення у великих таблицях (я б автоматично вимикав тригери та скидав індекси), а потім легко відтворював їх знову після закінчення обробки. Хтось чудово впорався з написанням декількох цих запитів.

    http://www.alberton.info/postgresql_meta_info.html

  • Кілька схем в одній базі даних, ви можете використовувати її, якщо у вашій базі даних велика кількість таблиць, ви можете розглядати схеми як категорії. Усі таблиці (незалежно від їх схеми) мають доступ до всіх інших таблиць та функцій, присутніх у батьківській базі даних.


+1 Я не можу повірити, що багаторазове успадкування так далеко.
Адам Гент,


4
select pg_size_pretty(200 * 1024)

спробував це в PostgreSQL 9.3помилковій помилці
Vivek S.

@WingedPanther У чому ваша помилка? Тут 9.3, він також має помилку (тоді помилок не було ще в 2009 році), виправлення полягає в тому, що вам потрібно передати ціле число у велике ціле число:pg_size_pretty((200 * 1024)::bigint)
Майкл Буен,

Так, річ у цьому
Vivek S.

3

pgcrypto : більше криптографічних функцій, ніж криптомодулі багатьох мов програмування, доступні безпосередньо з бази даних. Це робить криптографічні речі неймовірно простими просто виправитись.


3

Базу даних можна скопіювати за допомогою:

createdb -T old_db new_db

У документації сказано:

це (поки) не призначене як об'єкт загального призначення "БАЗА КОПІЮВАННЯ"

але це добре працює для мене і набагато швидше, ніж

створеноb new_db

pg_dump old_db | psql new_db


2

Зберігання пам'яті для викинутих даних / глобальних змінних

Ви можете створити табличну область, яка живе в оперативній пам’яті, і таблиці (можливо, не зареєстровані, в 9.1) у цій табличній області, щоб зберігати викинуті дані / глобальні змінні, якими ви хочете поділитися між сесіями.

http://magazine.redhat.com/2007/12/12/tip-from-an-rhce-memory-storage-on-postgresql/

Консультативні замки

Вони задокументовані в незрозумілій частині посібника:

http://www.postgresql.org/docs/9.0/interactive/functions-admin.html

Іноді це швидше, ніж отримання безлічі блокувань на рівні рядків, і їх можна використовувати для обходу випадків, коли FOR UPDATE не реалізовано (наприклад, рекурсивні запити CTE).


4
Створення табличного простору в оперативній пам'яті - надзвичайно погана ідея. Не робіть цього, ви ризикуєте серйозною та невиправною корупцією всієї бази даних. Використовуйте UNLOGGEDтаблиці.
Крейг Рінгер

2

Це мій улюблений список менш відомих функцій.

Транзакційний DDL

Майже кожен оператор SQL є транзакційним у Postgres. Якщо вимкнути автокомісію, можливо наступне:

drop table customer_orders;
rollback;
select *
from customer_orders;

Типи діапазонів та обмеження виключення

Наскільки мені відомо, Postgres - це єдина СУБД, яка дозволяє створити обмеження, яке перевіряє, чи два діапазони перекриваються. Прикладом може служити таблиця, що містить ціни на товари з датами "дійсний з" та "дійсний до":

create table product_price
(
   price_id      serial        not null primary key,
   product_id    integer       not null references products,
   price         numeric(16,4) not null,
   valid_during  daterange not null
);

Особливості NoSQL

У hstore подовжувальна пропонує гнучке і дуже швидко сховище ключів / значення , яке може бути використано , коли частині необхідності бази даних , щоб бути «схема-менш». JSON - це ще одна можливість зберігати дані без схем і

insert into product_price 
  (product_id, price, valid_during)
values 
  (1, 100.0, '[2013-01-01,2014-01-01)'),
  (1,  90.0, '[2014-01-01,)');


-- querying is simply and can use an index on the valid_during column
select price
from product_price
where product_id = 42
  and valid_during @> date '2014-10-17';

План виконання вищезазначеного на столі з 700 000 рядків:

Index Scan using check_price_range on public.product_price  (cost=0.29..3.29 rows=1 width=6) (actual time=0.605..0.728 rows=1 loops=1)
  Output: price
  Index Cond: ((product_price.valid_during @> '2014-10-17'::date) AND (product_price.product_id = 42))
  Buffers: shared hit=17
Total runtime: 0.772 ms

Щоб уникнути вставки рядків із перекриваються діапазонами дійсності, можна визначити просте (та ефективне) унікальне обмеження:

alter table product_price
  add constraint check_price_range 
  exclude using gist (product_id with =, valid_during with &&)

Нескінченність

Замість того, щоб вимагати "справжньої" дати далеко в майбутньому, Postgres може порівнювати дати з нескінченністю. Наприклад, коли не використовується діапазон дат, ви можете зробити наступне

insert into product_price 
  (product_id, price, valid_from, valid_until)
values 
  (1,  90.0, date '2014-01-01', date 'infinity');

Записні загальні вирази таблиці

Ви можете видалити, вставити та вибрати в одному твердженні:

with old_orders as (
   delete from orders
   where order_date < current_date - interval '10' year
   returning *
), archived_rows as (
   insert into archived_orders 
   select * 
   from old_orders
   returning *
)
select *
from archived_rows;

Вищевказане видалить усі замовлення старше 10 років, перемістить їх до archived_ordersтаблиці, а потім відобразить рядки, які були переміщені.


2

1.) Коли вам потрібно додати повідомлення до запиту, ви можете використовувати вкладений коментар

SELECT /* my comments, that I would to see in PostgreSQL log */
       a, b, c
   FROM mytab;

2.) Видаліть кінцеві пробіли з усіх полів textта та varcharз бази даних.

do $$
declare
    selectrow record;
begin
for selectrow in
select 
       'UPDATE '||c.table_name||' SET '||c.COLUMN_NAME||'=TRIM('||c.COLUMN_NAME||')  WHERE '||c.COLUMN_NAME||' ILIKE ''% '' ' as script
from (
       select 
          table_name,COLUMN_NAME
       from 
          INFORMATION_SCHEMA.COLUMNS 
       where 
          table_name LIKE 'tbl%'  and (data_type='text' or data_type='character varying' )
     ) c
loop
execute selectrow.script;
end loop;
end;
$$;

3.) Ми можемо використовувати функцію вікна для дуже ефективного видалення повторюваних рядків:

DELETE FROM tab 
  WHERE id IN (SELECT id 
                  FROM (SELECT row_number() OVER (PARTITION BY column_with_duplicate_values), id 
                           FROM tab) x 
                 WHERE x.row_number > 1);

Деякі оптимізовані версії PostgreSQL (з ctid):

DELETE FROM tab 
  WHERE ctid = ANY(ARRAY(SELECT ctid 
                  FROM (SELECT row_number() OVER (PARTITION BY column_with_duplicate_values), ctid 
                           FROM tab) x 
                 WHERE x.row_number > 1));

4.) Коли нам потрібно визначити стан сервера, ми можемо використовувати функцію:

SELECT pg_is_in_recovery();

5.) Отримайте команду DDL функцій.

select pg_get_functiondef((select oid from pg_proc where proname = 'f1'));

6.) Безпечна зміна типу даних стовпців у PostgreSQL

create table test(id varchar );
insert into test values('1');
insert into test values('11');
insert into test values('12');

select * from test
--Result--
id
character varying
--------------------------
1
11
12

З наведеної вище таблиці видно, що я використовував тип даних -
стовпець "ідентифікатор" для символів . Але це була помилка, тому що я завжди даю цілі числа як id. Тож використання varchar тут - погана практика. Тож спробуємо змінити тип стовпця на ціле число.

ALTER TABLE test ALTER COLUMN id TYPE integer;

Але воно повертається:

ПОМИЛКА: стовпець “id” не може бути автоматично переданий для введення цілочисельного стану SQL: 42804 Підказка: Вкажіть вираз USING для виконання перетворення

Це означає, що ми не можемо просто змінити тип даних, оскільки дані вже є в стовпці. Оскільки дані мають тип "змінюється за символами", postgres не може очікувати, що це ціле число, хоча ми ввели лише цілі числа. Отже, як запропонував postgres, ми можемо використовувати вираз «USING», щоб передати наші дані у цілі числа.

ALTER TABLE test ALTER COLUMN id  TYPE integer USING (id ::integer);

Це працює.

7.) Знати, хто підключений до бази даних
Це більш-менш команда моніторингу. Щоб знати, який користувач підключений до якої бази даних, включаючи їх IP та порт, використовуйте такий SQL:

SELECT datname,usename,client_addr,client_port FROM pg_stat_activity ;

8.) Перезавантаження конфігураційних файлів PostgreSQL без перезапуску сервера

Параметри конфігурації PostgreSQL містяться у спеціальних файлах, таких як postgresql.conf та pg_hba.conf. Часто вам може знадобитися змінити ці параметри. Але щоб деякі параметри набули чинності, нам часто потрібно перезавантажити файл конфігурації. Звичайно, це зробить перезапуск сервера. Але у виробничому середовищі не бажано перезапускати базу даних, яку використовують тисячі, лише для встановлення деяких параметрів. У таких ситуаціях ми можемо перезавантажити файли конфігурації без перезапуску сервера, використовуючи таку функцію:

select pg_reload_conf();

Пам'ятайте, це не працює для всіх параметрів, деякі зміни параметрів потребують повного перезапуску сервера, щоб вступити в силу.

9.) Отримання шляху до каталогу даних поточного кластера баз даних

Можливо, що в системі кілька екземплярів (кластер) PostgreSQL налаштовано, як правило, в різних портах або близько того. У таких випадках пошук того, який каталог (каталог фізичного сховища) використовується яким екземпляром, є напруженим завданням. У таких випадках ми можемо використати таку команду в будь-якій базі даних кластера, який нас цікавить, щоб отримати шлях до каталогу:

SHOW data_directory;

Цю саму функцію можна використовувати для зміни каталогу даних кластера, але для цього потрібно перезапустити сервер:

SET data_directory to new_directory_path;

10.) Знайти CHAR - це ДАТА чи ні

create or replace function is_date(s varchar) returns boolean as $$
begin
  perform s::date;
  return true;
exception when others then
  return false;
end;
$$ language plpgsql;

Використання: наступне поверне значення True

select is_date('12-12-2014')
select is_date('12/12/2014')
select is_date('20141212')
select is_date('2014.12.12')
select is_date('2014,12,12')

11.) Змініть власника в PostgreSQL

REASSIGN OWNED BY sa  TO postgres;

12.) PGADMIN PLPGSQL DEBUGGER

Добре пояснено тут


+1 для 2 , 3 , 6 , 9

0

Зручно перейменовувати стару базу даних, а не mysql. Просто використовуючи таку команду:

ALTER DATABASE name RENAME TO new_name
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.