pgbench
یکی از ابزار های خوب برای seed - dummy data - و نمایش تعداد و سرعت همین ابزار هست
insert
بعد از طراحی دیتابیس می تونیم با استفاده از ai دیتای رندوم بسازیم و با یه دیتابیس پر دیتا ، اون رو آنالیز کنیم و بهبود بدیم
فرض کنیم که میخواهیم ۲ جدول زیر رو پر کنیم :
-- public.contract definition
CREATE TABLE public.contract ( id uuid DEFAULT gen_random_uuid() NOT NULL, user_id varchar(60) NOT NULL, external_id varchar(60) DEFAULT gen_random_uuid() NOT NULL, max_daily_transaction int2 NULL, max_monthly_transaction int2 NULL, max_transaction_amount int8 NULL, withdrawal_permission bool DEFAULT false NOT NULL, bank varchar(60) NULL, bill_payment_permission bool DEFAULT false NOT NULL, provider varchar(60) NULL, status varchar(60) NULL, provider_code varchar(60) NULL, provider_reference varchar(60) NULL, start_time timestamp NULL, expire_time timestamp NULL, create_time timestamp NULL, update_time timestamp DEFAULT CURRENT_TIMESTAMP NULL, deposit_number varchar(60) NULL, CONSTRAINT contract_pkey PRIMARY KEY (id));
CREATE INDEX bank_index ON public.contract USING btree (bank);
CREATE INDEX idx_external_id ON public.contract USING btree (external_id);
CREATE INDEX idx_provider_reference ON public.contract USING btree (provider_reference);
CREATE INDEX provider_code_index ON public.contract USING btree (provider_code);
CREATE UNIQUE INDEX provider_code_unique ON public.contract USING btree (provider_code);
CREATE INDEX provider_index ON public.contract USING btree (provider);
CREATE INDEX status_index ON public.contract USING btree (status);
CREATE UNIQUE INDEX unique_external_id ON public.contract USING btree (external_id);
CREATE INDEX user_id_index ON public.contract USING btree (user_id);
-- public.pay definition
CREATE TABLE public.pay ( id uuid DEFAULT gen_random_uuid() NOT NULL, external_id varchar(60) DEFAULT gen_random_uuid() NOT NULL, contract_id uuid NOT NULL, reference_id varchar(60) NULL, amount int8 NOT NULL, status varchar(60) NULL, create_time timestamp NULL, transaction_time timestamp NULL, peyman_batch varchar(60) NULL, update_time timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, destination_bank varchar(100) NULL, destination_deposit varchar(100) NULL, source_bank varchar(100) NULL, source_deposit varchar(100) NULL, CONSTRAINT pay_pkey PRIMARY KEY (id), CONSTRAINT fk_contract_id FOREIGN KEY (contract_id) REFERENCES public.contract(id));
CREATE INDEX contract_id_index ON public.pay USING btree (contract_id);
CREATE INDEX status_index_pay ON public.pay USING btree (status);
CREATE UNIQUE INDEX unique_external_id_pay ON public.pay USING btree (external_id);
میتونیم با استفاده از این ۲ تا فایل ، داده رو پر کنیم :
برای contract:
-- file: seed_contracts.sql
\set user_id random(1, 1000000)
\set max_daily_transaction random(1, 100)
\set max_monthly_transaction random(1, 3000)
\set max_transaction_amount random(1000, 1000000)
\set withdrawal_permission random(0, 1)
\set bill_payment_permission random(0, 1)
INSERT INTO public.contract
(user_id, external_id, max_daily_transaction, max_monthly_transaction, max_transaction_amount,
withdrawal_permission, bank, bill_payment_permission, provider, status, provider_code,
provider_reference, start_time, expire_time, create_time, deposit_number)
VALUES
(:user_id,
md5(random()::text), -- random external_id
:max_daily_transaction,
:max_monthly_transaction,
:max_transaction_amount,
(:withdrawal_permission)::boolean,
'bank_' || md5(random()::text),
(:bill_payment_permission)::boolean,
'provider_' || md5(random()::text),
'active',
'provcode_' || md5(random()::text),
'provref_' || md5(random()::text),
now(),
'2026-01-01 00:00:00',
now(),
'dep_' || md5(random()::text)
);برای pay :
-- file: seed_pay.sql
\set amount random(1000, 1000000)
INSERT INTO public.pay
(external_id, contract_id, reference_id, amount, status, create_time, transaction_time,
peyman_batch, destination_bank, destination_deposit, source_bank, source_deposit)
VALUES
(
md5(random()::text), -- external_id
(SELECT id FROM public.contract ORDER BY random() LIMIT 1), -- random contract_id
md5(random()::text), -- reference_id
:amount,
'pending',
now(),
now(),
'batch_' || md5(random()::text),
'dest_bank_' || md5(random()::text),
'dest_dep_' || md5(random()::text),
'src_bank_' || md5(random()::text),
'src_dep_' || md5(random()::text)
);و در نهایت با دستور زیر اعمال میکنیم :
pgbench -n -f pgbench_pay.sql -T 30 -d database_name
pg_stats
pg_stat_database
اطلاعات جنریک دیتابیس ها رو میده
SELECT * FROM pg_stat_database;
اگر نسیت زیر کمتر از 95 درصد بود باید به شیرد بافر اضافه کنیم
SELECT datname,
blks_hit::float / (blks_hit + blks_read) AS cache_hit_ratio,
blks_hit, blks_read
FROM pg_stat_database
WHERE blks_hit + blks_read > 0;
pg_stat_statements
آمار کوییری هایی که زدیم رو میگه ، مثلا بیشتری کوییری های اینسرت یا سلکت و یا …
چرا مفیده؟ می تونیم ببینیم کدوم کوییری بیشتر استفاده شده ، کوییری هایی که تو ۶ ماه بیشترین استفاده شده ، میشه با مدیریت ایندکس بهینش کرد ، قطعا کوییری که خیلی سرعتش پایینه اما به ندرت استفاده میشه مهم نیست ، مهم کوییری هست که شاید سرعتش معمولی باشه ولی اونقدر استفاده میشه اگر از معمولی اون رو بکنیم سریع ، کلی جلو می افتیم .
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
SELECT *
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;ستون های مهم :
- query --- متن کوییری
- calls --- تعداد بار های فراخوانی
- total_exec_time --- زمانی که صرف شده
- rows --- تعداد سطر هایی که میاره ، میشه با calls مقایسه کرد
- shared_blks_hit, shared_blks_read, shared_blks_written --- چقد از کش استفاده می کنیم و یا از io