Equnix PostgreSQL Query Tuning
Equnix PostgreSQL Query Tuning
Query Tuning
Topic
1. Slow Query
2. Indexing
3. SQL Tuning
4. Explain
Query Tuning - Why
❖ IDLE
postgres=#select now()-query_start as waiting_duration,
pid,client_addr,query from pg_stat_activity where state =
'idle' order by 1 desc;
Query Tuning - PG_LOG
1. log_destination = 'stderr'
2. logging_collector = on #change require restart
3. log_directory = 'pg_log'
4. log_file_name = 'postgresql-%Y-%m-%d_%H%M%S.log'
5. log_rotation_age = 1d
6. log_rotation_size = 10MB
7. log_min_error_statement = error
8. log_min_duration_statement = 5000 #milliseconds; 0 = all; -1 = disable
9. log_line_prefix = '|%m|%r|%a|%d|%u|%e|'
10. log_statment = 'mod'
Query Tuning - pg_stat_statements
B-Tree Index
❖ Balance Tree though
❖ Default Index in PostgreSQL
❖ Unless we create index using “using” other index type
❖ B-trees can handle equality and range queries on data that can be
sorted into some ordering (prefer integer)
❖ Query planner will consider using a B-tree index whenever an indexed
column is involved in a comparison using one of these operators:
➢ <
<=
=
>=
>
INDEX - HASH
HASH Index
❖ Create Index using “using” keyword
❖ Hash indexes can only handle simple equality (=) comparisons
❖ Hash index operations are not presently WAL-logged
❖ Hash indexes might need to be rebuilt with REINDEX after a database
crash if there were unwritten changes
❖ That’s why HASH index deprecated because btree is more powerful
INDEX - GIST
GIST Index
❖ Create Index using “using” keyword
❖ Generalized Search Tree
❖ For Text Search (Array Type)
❖ A GiST index is lossy, meaning that the index may produce false
matches
❖ Although select is lossy, but GIST is Faster than GIN when UPDATE
❖ Do not use in RDBMS (transaction)
❖ Good for document database with json/jsonb data type
INDEX - SP-GIST
SP-GIST Index
❖ Create Index using “using” keyword
❖ like GIST Index
❖ SP-GiST permits implementation of a wide range of different
non-balanced disk-based data structures, such as quadtrees, k-d trees,
and radix trees (tries)
INDEX - GIN
GIN Index
❖ Create Index using “using” keyword
❖ Generalized Inverted Index
❖ For text search (Array Type)
❖ GIN indexes are not lossy for standard queries
❖ Still do not use in RDBMS (unless standard queries text search)
❖ GIN index lookups are about three times faster than GiST
❖ GIN indexes take about three times longer to build than GiST
❖ GIN indexes are moderately slower to update than GiST indexes, but
about 10 times slower if fast-update support was disabled
❖ GIN indexes are two-to-three times larger than GiST indexes
❖ Good for select JSON/JSONB data type
INDEX - BRIN
BRIN Index
❖ Create Index using “using” keyword
❖ Block Range Indexes
❖ BRIN indexes can speed things up a lot than B-Tree Index
❖ Smaller than B-Tree Index
❖ Decrease up to 25% in disk usage
❖ But only if your data has a strong natural ordering to begin with (date)
INDEX - MISSING INDEX
For Example:
Write the query as
SELECT id, first_name, last_name, age, subject FROM student_details;
Instead of:
SELECT * FROM student_details;
SQL Tuning - HAVING
SQL Tips and Trick? - HAVING
HAVING clause is used to filter the rows after all the rows are selected. It is
just like a filter. Do not use HAVING clause for any other purposes.
For Example: Write the query as
For Example:
Instead of:
SELECT subject, count(subject)
FROM student_details
GROUP BY subject
HAVING subject!= 'Vancouver' AND subject!= 'Toronto';
SQL Tuning - SUBQUERY
SQL Tips and Trick? - SUBQUERY
Sometimes you may have more than one subqueries in your main query.
Try to minimize the number of subquery block in your query.
For Example:
Write the query as
SELECT name
FROM employee
WHERE (salary, age ) = (SELECT MAX (salary), MAX (age)
FROM employee_details)
AND dept = 'Electronics';
Instead of:
SELECT name
FROM employee
WHERE salary = (SELECT MAX(salary) FROM employee_details)
AND age = (SELECT MAX(age) FROM employee_details)
AND emp_dept = 'Electronics';
SQL Tuning - IN and EXISTS
Example IN
SELECT * FROM Orders WHERE ProductNumber IN (1, 10, 100);
Example EXISTS
SELECT * FROM Orders WHERE EXISTS ( SELECT * FROM Orders WHERE
ProductNumber > 10);
SQL Tuning - IN
Example IN
postgres=# explain analyze select * from test where i in (select i from test where i > 999);
QUERY PLAN
----------------------------------------------------------------------------------
Merge Semi Join (cost=0.87..782829.40 rows=9999031 width=72) (actual
time=0.342..7745.913 rows=9999001 loops=1)
Merge Cond: (test.i = test_1.i)
-> Index Scan using test_pkey on test (cost=0.43..303935.09 rows=9999977
width=72) (actual time=0.013..2030.917 ro
ws=10000000 loops=1)
-> Index Only Scan using test_pkey on test test_1 (cost=0.43..328906.48
rows=9999031 width=4) (actual time=0.025..
1924.827 rows=9999001 loops=1)
Index Cond: (i > 999)
Heap Fetches: 9999001
Planning time: 14.564 ms
Execution time: 8113.224 ms
(8 rows)
SQL Tuning - EXISTS
Example EXISTS
postgres=# explain analyze select * from test where exists (select * from test where i > 999);
QUERY PLAN
----------------------------------------------------------------------------------
Result (cost=0.02..144247.79 rows=9999977 width=72) (actual time=0.021..1947.417
rows=10000000 loops=1)
One-Time Filter: $0
InitPlan 1 (returns $0)
-> Seq Scan on test test_1 (cost=0.00..169247.71 rows=9999031 width=0)
(actual time=0.012..0.012 rows=1 loops=1)
Filter: (i > 999)
-> Seq Scan on test (cost=0.00..144247.77 rows=9999977 width=72) (actual
time=0.007..893.664 rows=10000000 loops=1
)
Planning time: 0.127 ms
Execution time: 2306.229 ms
(8 rows)
SQL Tuning - UNION and UNION ALL
Example UNION
SELECT /*+ FIRST_ROWS */ PI_FORMAT.F_CAR(A.CAR) AS CAR, A.KD_KANTOR,
A.IMPNAMA, B.PPJKNAMA, F_UR_TASK(A.STATUS),
TO_CHAR(A.WK_STATUS,'DD/MM/YYYY HH24:MI:SS') AS WK_STATUS ,
COALESCE(A.JMLARTAS,0), A.SEQ, A.ID_TRADER
FROM TBLTRACKINGHDR A INNER JOIN TBLPIBHDR B ON
A.CUSDECID=B.CUSDECID
LEFT JOIN TBLORGANIZATION d ON A.IMPNPWP = D.NOIDORG
WHERE (A.ID_TRADER = '' OR D.ORGID = '13054') AND A.TAHUN
IN('2017') AND (date_trunc('day', A.WK_STATUS) BETWEEN
TO_DATE('01/01/2017','DD/MM/YYYY') AND
TO_DATE('05/01/2017','DD/MM/YYYY')) ORDER BY A.WK_STATUS DESC
COST: 15 - 20 detik
SQL Tuning - WHERE
Summary INDEXES
❖ Eliminate Sequential Scans (Seq Scan) by adding indexes (unless table
size is small)
❖ If using a multicolumn index, make sure you pay attention to order in
which you define the included columns
❖ Try to use indexes that are highly selective on commonly-used data.
This will make their use more efficient
SQL Tuning - WHERE
Understand EXPLAIN
❖ The EXPLAIN command is by far the must have when it comes to tuning
queries
❖ It tells you what is really going on
❖ Get a nice understanding of the informations given by this command,
know how to use this information, and fix your queries so that they
work faster.
❖ ANALYZE/ANALYSE (PostgreSQL support american and british language)
SQL Tuning - Explain
Understand EXPLAIN
postgres=# explain analyze select * from test;
QUERY PLAN
--------------------------------------------------------------------
Seq Scan on test (cost=0.00..144247.77 rows=9999977 width=72)
(actual time=0.011..4172.020 rows=10000000 loops=1)
Planning time: 0.041 ms
Execution time: 4608.374 ms
(3 rows)
SQL Tuning - Explain
Understand EXPLAIN
❖ Node
➢ logical unit of work (a “step” if you will) with an associated cost and execution time
❖ Seq scan
➢ it’s mean sequential scan (doesn’t use index)
❖ Index Scan
➢ it’s mean scan using index
❖ Cost
➢ cost to get the first row: 0.00
➢ cost to get all rows: 144247.77
➢ the number is “page cost” unit
SQL Tuning - Explain
Understand EXPLAIN
❖ Rows
➢ number of rows in table (cost: planner read sample rows; actual:real read rows)
❖ Width
➢ average width of a row
➢ in bytes
❖ Actual time
➢ actual cost time
❖ Planning time
➢ query planner thinks execution time
❖ Execution time
➢ real execution time
SQL Tuning - Explain
QUERY PLAN
--------------------------------------------------------------------
Index Scan using test_pkey on test (cost=0.43..8.45 rows=1
width=72) (actual time=0.015..0.015 rows=1 loops=1)
Index Cond: (i = 999)
Planning time: 0.081 ms
Execution time: 0.040 ms
(4 rows)
SQL Tuning - Explain FORMAT
QUERY PLAN
--------------------------------------------------------------------
[ +
{ +
"Plan": { +
"Node Type": "Index Scan", +
"Scan Direction": "Forward",+
"Index Name": "test_pkey", +
"Relation Name": "test", +
"Alias": "test", +
"Startup Cost": 0.43, +
"Total Cost": 8.45, +
"Plan Rows": 1, +
"Plan Width": 72, +
"Index Cond": "(i = 999)" +
} +
} +
]
(1 row)
Question