これがまだ投稿されていないことに驚いています。Postgresで知っている興味深いトリックはありますか?あいまいな構成オプションとスケーリング/パフォーマンスのトリックは特に歓迎されます。
対応するMySQLスレッドの9つのコメントを打ち負かすことができると確信しています:)
これがまだ投稿されていないことに驚いています。Postgresで知っている興味深いトリックはありますか?あいまいな構成オプションとスケーリング/パフォーマンスのトリックは特に歓迎されます。
対応するMySQLスレッドの9つのコメントを打ち負かすことができると確信しています:)
回答:
postgresはMySQLよりもはるかに正気なので、報告する「トリック」はそれほど多くありません;-)
マニュアルにはいくつかの素晴らしい持っているパフォーマンスのヒントを。
覚えておくべき他のいくつかのパフォーマンス関連事項:
設定やパフォーマンス自体に関係のない、便利だと思ったことがいくつかあります。
現在何が起こっているかを確認するには:
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)
最も簡単なトリックは、PostgreSQLが(まだ行っていない場合)とそれを仕事に多くのRAMを与えることだけである(別に設定すると当然の適切なインデックスを使用してから)かなり良く実行できます。ほとんどのデフォルトのインストールでは、shared_buffersの値が低すぎます(私の意見では)。設定できます
shared_buffers
postgresql.confにあります。この数値を128で割ると、postgresが要求できるメモリ量(MB単位)の概算が得られます。あなたがそれを十分に上げるならば、これはpostgresqlを飛ばすでしょう。postgresqlを再起動することを忘れないでください。
Linuxシステムでは、postgresqlが再び起動しない場合は、kernel.shmmaxの制限に達している可能性があります。で高く設定する
sysctl -w kernel.shmmax=xxxx
これを起動間で持続させるには、kernel.shmmaxエントリを/etc/sysctl.confに追加します。
Postgresqlのトリックの全体はここで見つけることができます:
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型にキャストできます。
コピー
始めます。SQLiteからPostgresに切り替えるときはいつも、非常に大きなデータセットがいくつかあります。重要なのは、INSERTを実行するのではなく、COPYFROMを使用してテーブルをロードすることです。ドキュメントを参照してください:
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での一括挿入の高速化?
generate_series
、ついにダミーの行セットを生成するクリーンな方法です。LIMIT
サブクエリの句で相関値を使用する機能:
SELECT (
SELECT exp_word
FROM mytable
OFFSET id
LIMIT 1
)
FROM othertable
Postgresで私が本当に気に入っていることの1つは、列でサポートされているデータ型のいくつかです。たとえば、ネットワークアドレスと配列を格納するために作成された列タイプがあります。これらの列タイプに対応する関数(ネットワークアドレス/配列)を使用すると、MySQLまたは他のデータベースエンジンのコードを介して結果を処理することによって実行する必要があるクエリ内で多くの複雑な操作を実行できます。
あなたがそれらを知るようになると、配列は本当にクールです。ページ間にいくつかのハイパーリンクを保存したいとします。次のようなテーブルの作成について考えることから始めることができます。
CREATE TABLE hyper.links (
tail INT4,
head INT4
);
テール列にインデックスを付ける必要があり、たとえば200,000,000のリンク行がある場合(ウィキペディアが提供するように)、巨大なテーブルと巨大なインデックスがあります。
ただし、PostgreSQLでは、代わりに次のテーブル形式を使用できます。
CREATE TABLE hyper.links (
tail INT4,
head INT4[],
PRIMARY KEY(tail)
);
リンクのすべてのヘッドを取得するには、次のようなコマンドを送信できます(uncest()は8.4以降の標準です)。
SELECT unnest(head) FROM hyper.links WHERE tail = $1;
このクエリは、最初のオプションと比較すると驚くほど高速です(unnest()は高速で、インデックスははるかに小さいです)。さらに、特に配列が長すぎてトーストテーブルに圧縮されていない場合、テーブルとインデックスが占めるRAMメモリとHDスペースははるかに少なくなります。配列は本当に強力です。
注:unnest()は配列から行を生成しますが、array_agg()は行を配列に集約します。
マテリアライズドビューの設定は非常に簡単です。
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_viewの列と値を持つ新しいテーブルmy_matviewが作成されます。次に、データを最新の状態に保つために、または怠惰な場合は、トリガーまたはcronスクリプトを設定できます。
TRUNCATE my_matview;
INSERT INTO my_matview SELECT * FROM my_view;
Inheritance..infact多重継承(多くのWebフレームワークがpostgresを操作するときに実装する1対1の関係継承ではなく、親子の「継承」のように)。
PostGIS(空間拡張)、ジオメトリ関数の包括的なセットを提供し、箱から出してストレージを調整する素晴らしいアドオン。多くのオープンソースgeoライブラリ(OpenLayers、MapServer、Mapnikなど)で広く使用されており、MySQLの空間拡張よりもはるかに優れています。
C、Python、Perlなどのさまざまな言語でプロシージャを作成します(db-adminではなく開発者であれば、コーディングが容易になります)。
また、すべてのプロシージャは外部に(モジュールとして)格納でき、指定した引数によって実行時に呼び出すかインポートすることができます。そうすれば、コードをソース管理し、コードを簡単にデバッグできます。
データベースに実装されているすべてのオブジェクト(つまり、テーブル、制約、インデックスなど)に関する巨大で包括的なカタログ。
いくつかのクエリを実行して、すべてのメタ情報(たとえば、制約名とそれらが実装されているフィールド、インデックス名など)を取得することは、常に非常に役立つと思います。
私にとっては、新しいデータをロードしたり、大きなテーブルで大規模な更新を行ったり(トリガーを自動的に無効にし、インデックスを削除したり)、処理の終了後に簡単に再作成する必要がある場合に、すべてが非常に便利になります。誰かがこれらのクエリのいくつかを書くという素晴らしい仕事をしました。
1つのデータベースに複数のスキーマがあり、データベースに多数のテーブルがある場合に使用できます。スキーマはカテゴリと考えることができます。すべてのテーブル(スキーマに関係なく)は、親データベースに存在する他のすべてのテーブルと関数にアクセスできます。
「explainanalyze」出力を解読する方法を学ぶ必要はありません。ツールがあります:http://explain.depesz.com
使い捨てデータ/グローバル変数用のメモリストレージ
RAMに存在するテーブルスペースと、そのテーブルスペースにテーブル(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クエリなど)を回避するために使用できます。
UNLOGGED
テーブルを使用します。
これは、あまり知られていない機能の私のお気に入りのリストです。
PostgresではほぼすべてのSQLステートメントがトランザクションです。自動コミットをオフにすると、次のことが可能になります。
drop table customer_orders;
rollback;
select *
from customer_orders;
私の知る限り、Postgresは、2つの範囲が重複しているかどうかをチェックする制約を作成できる唯一のRDBMSです。例は、「有効開始日」と「有効期限」の日付を持つ製品価格を含むテーブルです。
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
);
このhstore
拡張機能は、データベースの一部を「スキーマレス」にする必要がある場合に使用できる、柔軟で非常に高速なキー/値ストアを提供します。JSONは、スキーマを使用せずにデータを保存するためのもう1つのオプションです。
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');
1つのステートメントで、削除、挿入、および選択を行うことができます。
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
テーブルに移動してから、移動された行を表示します。
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」
列に「文字変化」というデータ型を使用したことがわかります。しかし、私は常に整数を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がDATEであるかどうかを確認します
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
mysqlではなく、古いデータベースの名前を変更すると便利です。次のコマンドを使用するだけです。
ALTER DATABASE name RENAME TO new_name