22 Ekim 2024 Salı

postgresql.conf İyileştirmeleri

Örnek
Şöyle yaparız
# Memory settings
shared_buffers = 16GB
work_mem = 64MB
maintenance_work_mem = 2GB
effective_cache_size = 48GB

# Connection settings
max_connections = 500

# Checkpoint settings
checkpoint_segments = 32
checkpoint_completion_target = 0.9

# WAL settings
wal_buffers = 16MB
max_wal_size = 4GB

# Logging settings
log_min_duration_statement = 5000  # Log queries taking longer than 5 seconds

20 Haziran 2024 Perşembe

Index Scan

Giriş
Index Only Scans'den farklıdır

Örnek
Elimizde şöyle bir tablo olsun
postgres=# \d users
                              Table "public.users"
    Column    |              Type              | Collation | Nullable | Default
--------------+--------------------------------+-----------+----------+---------
 firstname    | character varying(300)         |           |          |
 lastname     | character varying(300)         |           |          |
 name         | character varying(300)         |           |          |
 createdat    | timestamp(6) without time zone |           |          |
 emailaddress | character varying(300)         |           |          |
 lockout      | boolean                        |           |          |
 status       | numeric(30,0)                  |           |          |
 lockout_date | timestamp(6) without time zone |           |          |
Indexes:
    "users_at_idx_1" btree (lockout, status, createdat DESC NULLS LAST)
Burada 3 tane sütun birlikte bir indeksi oluşturuyor.. Select * ile sorgulayalım.  
SELECT
 *
FROM
 users
WHERE
 lockout IN (true)
 AND status IN (3, 4)
 AND createdat IN ('2023-05-18 00:00:00', '2023-06-19 00:00:00');
 Çıktı şöyle. Index kullanımı görülebilir.
Index Scan using users_at_idx_1 on public.users  (cost=0.56..24879.59 rows=7255 width=72) (actual time=0.132..33.704 rows=3686 loops=1)
  Output: firstname, lastname, name, createdat, emailaddress, lockout, status, lockout_date
  Index Cond: ((users.lockout = true) AND (users.status = ANY ('{3,4}'::numeric[])) AND (users.createdat = ANY ('{"2023-05-18 00:00:00","2023-06-19 00:00:00"}'::timestamp without time zone[])))
  Buffers: shared hit=48 read=3653
Planning:
  Buffers: shared hit=53
Planning Time: 0.584 ms
Execution Time: 34.102 ms



15 Ocak 2024 Pazartesi

Generalized Inverted Index - GIN Index - JSONB Sütun Tipine Göre Index Full Text Search İçindir

Giriş
JSONB Sütun Tipi için 2 çeşit GIN index yaratılabilir. Açıklaması şöyle
A set of GIN-specific operators that can be used in a query depends on the operator class specified at index creation. For JSONB, supported classes are:

jsonb_ops — the default operator class, which provides two categories of operators: checking the existence of keys and checking the existence of values based on JSONPath expressions or key-value pairs.
jsonb_path_ops — provides only the latter category and offers better performance for these operators.

jsonb_path_ops Tipi
Açıklaması şöyle
Create a GIN index on the JSONB column using the jsonb_path_ops operator class. This limits the operator to only @>, but that operator allows equality comparisons on any number of properties located at different levels within the JSONB document in a single WHERE criteria.
Örnek
Şöyle yaparız
CREATE TABLE sample_jsonb (id serial NOT NULL PRIMARY KEY, data jsonb);

INSERT INTO sample_jsonb (data) VALUES 
('{"name":"First", "count":12, "orderDate":"2022-03-03T12:14:01", "extra":"some text"}');

INSERT INTO sample_jsonb (data) VALUES
('{"name": "Second", "count": 23, "orderDate": "2022-04-03T15:17:01"}');

CREATE INDEX sample_jsonb_path_ops_idx
ON sample_jsonb USING GIN (data jsonb_path_ops);

-- select all rows where the name property is equal to "First" a
SELECT * FROM sample_jsonb WHERE data @> '{"name":"First"}'::jsonb 

-- select all rows where count is greater than 15
SELECT * FROM sample_jsonb WHERE data @@ '$.count > 15'

Örnek
@> operator yani containment operator kullanıyorsak gerekir. Bir index oluşturalım
CREATE INDEX gin_data ON books_data using gin(data); 
Bir sorgu çalıştıralım.  Gin indeksinin kullanıldığını görebiliriz.
EXPLAIN ANALYZE SELECT * FROM books_data WHERE data @> '{"author" : "Mark Figueroa"}';

27 Aralık 2023 Çarşamba

ROW LEVEL SECURITY - CREATE POLICY veya DROP POLICY

Giriş
Açıklaması şöyle
Row Level Security (RLS) lets you define access control policies at the row level within tables. This means that you can specify which users can SELECT, INSERT, UPDATE, or DELETE rows based on the actual data within the row.
Örnek
Elimizde şöyle bir tablo olsun
CREATE TABLE client (
    client_id PRIMARY KEY,     
    client_name VARCHAR(255) NOT NULL,
    email VARCHAR(255),               
    registration_date DATE DEFAULT CURRENT_DATE 
);
ROW LEVEL SECURITY kullanmak için şöyle yaparız
ALTER TABLE client ENABLE ROW LEVEL SECURITY;
ROW LEVEL SECURITY kullanmak için şöyle yaparız
DROP POLICY IF EXISTS client_isolation_policy ON client;
Sonra şöyle yaparız
CREATE POLICY client_isolation_policy on client
  USING (current_user =CONCAT('appuser_', client_id::text));
apppuser + client_id sütun değeri current_user ile aynı ise bu satır kullanıcıya gösterilir

Yeni bir kullanıcı yaratalım
create user appuser_1001 WITH ENCRYPTED PASSWORD 'password';

GRANT connect on database sample_db to appuser_1001;

GRANT USAGE ON SCHEMA public TO appuser_1001;

GRANT select on all tables in schema public to appuser_1001;

GRANT INSERT,UPDATE ON all tables in schema public TO appuser_1001;
root veya postgres kullanıcı etkilenmez. Her şeyi görebilir
select * from client c ;

client_id|client_name|email          |registration_date|
---------+-----------+---------------+-----------------+
     1001|Client 1001|abc@example.com|       2023-10-17|
     1002|Client 1002|abc@example.com|       2023-10-17|
appuser_1001 kullanıcısı sadece 1001 değerine sahip satırları görebilir.
select * from client c ;

client_id|client_name|email          |registration_date|
---------+-----------+---------------+-----------------+
     1001|Client 1001|abc@example.com|       2023-10-17|







Sütun Tipleri - ULID - Universally Unique Lexicographically Sortable Identifier

Bu tipi ilk olarak Performance of ULID and UUID in Postgres Database yazısında gördüm. Açıklaması şöyle
ULIDs contain a 48-bit timestamp followed by 80 bits of random data. The timestamp allows ULIDs to be sorted, which works much better with the b-tree data structure databases use for indexing.”
UUID performans kaybına sebep oluyor. Diğer seçenekler şöyle
ULIDs
Snowflake
Composite keys