
SO SÁNH TỔNG QUÁT HIỆU SUẤT CÁC TIỆN ÍCH TRONG POSTGRES
(VIEWS, PROCEDURE, FUNCTION, CURSOR,...)
Các tập dữ liệu
+ Tập dữ liệu nhỏ:
+ Tập dữ liệu lớn:
1. so sánh giữa view vs martiriazlize view
Tạo một view và một materialized view từ bảng customer và address.
-- Tạo View
DROP VIEW IF EXISTS customer_with_address;
CREATE VIEW customer_with_address AS
SELECT c.customer_id, c.first_name, c.last_name, ci.city, co.country
FROM customer c
JOIN address a ON c.address_id = a.address_id
JOIN city ci ON a.city_id = ci.city_id
JOIN country co ON ci.country_id = co.country_id;
-- Tạo Materialized View
DROP MATERIALIZED VIEW IF EXISTS customer_with_address_mat;
CREATE MATERIALIZED VIEW customer_with_address_mat AS
SELECT c.customer_id, c.first_name, c.last_name, ci.city, co.country
FROM customer c
JOIN address a ON c.address_id = a.address_id
JOIN city ci ON a.city_id = ci.city_id
JOIN country co ON ci.country_id = co.country_id;
Ta sẽ thực hiện 2 câu query sau để test:
-- Thực hiện query
EXPLAIN ANALYSE SELECT * FROM customer_with_address WHERE last_name = 'Smith';
EXPLAIN ANALYSE SELECT * FROM customer_with_address_mat WHERE last_name = 'Smith';
Kết quả test tập dữ liệu nhỏ:
Views thường:
Materialize view:
Kết quả tập dữ liệu lớn
View thường:
2. so sánh giữa function bình thường và function có dùng cursor
Tạo hai function: một không dùng CURSOR và một dùng CURSOR.
-- Function không dùng CURSOR
CREATE OR REPLACE FUNCTION get_customers_normal()
RETURNS TABLE(customer_id INT, first_name VARCHAR, last_name VARCHAR, city VARCHAR, country VARCHAR) AS $$
BEGIN
RETURN QUERY
SELECT c.customer_id, c.first_name, c.last_name, ci.city, co.country
FROM customer c
JOIN address a ON c.address_id = a.address_id
JOIN city ci ON a.city_id = ci.city_id
JOIN country co ON ci.country_id = co.country_id;
END; $$ LANGUAGE plpgsql;
-- FUNCTION dùng CURSOR
CREATE OR REPLACE FUNCTION get_customers_cursor()
RETURNS TABLE(customer_id INT, first_name VARCHAR, last_name VARCHAR, city VARCHAR, country VARCHAR) AS $$
DECLARE
customer_cur CURSOR FOR
SELECT c.customer_id, c.first_name, c.last_name, ci.city, co.country
FROM customer c
JOIN address a ON c.address_id = a.address_id
JOIN city ci ON a.city_id = ci.city_id
JOIN country co ON ci.country_id = co.country_id;
BEGIN
OPEN customer_cur;
LOOP
FETCH customer_cur INTO customer_id, first_name, last_name, city, country;
EXIT WHEN NOT FOUND;
RETURN NEXT;
END LOOP;
CLOSE customer_cur;
END; $$ LANGUAGE plpgsql;
Ta chạy 2 câu query sau để test:
EXPLAIN ANALYSE SELECT * FROM get_customers_normal();
EXPLAIN ANALYSE SELECT * FROM get_customers_cursor();
Test trên tập nhỏ:
+ Không dùng cursor:
+ Dùng cursor:
Test trên tập lớn:
+ Không dùng cursor:
+ Dùng cursor:
Tuy nhiên, phía trên là chạy lúc đầu, có thể do đã được cache do query sau nên dùng cursor sẽ có execution time nhanh hơn, dưới đây là query lại lần nữa:
+ Không dùng cursor
+ Dùng cursor:
Kết quả gần như tương tự nhau, mặc dùng dùng cursor sẽ nhỉnh hơn một chút.
3. so sánh giữa dùng view vs martiriazlize view vs function dùng cursor vs dunction không dùng cursor vs dùng procedure
4. so sánh 3 câu query: join với table, join với function, join với view
Đầu tiên ta tạo mới function và view như sau:
CREATE OR REPLACE VIEW customer_address_view AS
SELECT c.customer_id, c.first_name, c.last_name, a.address
FROM customer c
JOIN address a ON c.address_id = a.address_id;
CREATE OR REPLACE FUNCTION get_customers_with_address()
RETURNS TABLE(customer_id INT, first_name VARCHAR, last_name VARCHAR, address VARCHAR) AS $$
BEGIN
RETURN QUERY
SELECT c.customer_id, c.first_name, c.last_name, a.address
FROM customer c
JOIN address a ON c.address_id = a.address_id;
END;
$$
LANGUAGE plpgsql;
Test với tập nhỏ
Join với bảng bình thường:
EXPLAIN ANALYSE SELECT c.customer_id, c.first_name, c.last_name, subquery.address
FROM (
SELECT c.customer_id, c.first_name, c.last_name, a.address
FROM customer c
JOIN address a ON c.address_id = a.address_id
) subquery
JOIN customer c ON subquery.customer_id = c.customer_id;
Join với view
EXPLAIN ANALYZE SELECT c.customer_id, c.first_name, c.last_name, v.address FROM customer c JOIN customer_address_view v ON c.customer_id = v.customer_id;
Join với function
EXPLAIN ANALYZE SELECT c.customer_id, c.first_name, c.last_name, f.address FROM customer c JOIN get_customers_with_address() f ON c.customer_id = f.customer_id;
Test với tập lớn
Join với bảng bình thường:
EXPLAIN ANALYSE SELECT c.customer_id, c.first_name, c.last_name, subquery.address
FROM (
SELECT c.customer_id, c.first_name, c.last_name, a.address
FROM customer c
JOIN address a ON c.address_id = a.address_id
) subquery
JOIN customer c ON subquery.customer_id = c.customer_id;
Join với view
EXPLAIN ANALYZE
SELECT c.customer_id, c.first_name, c.last_name, v.address
FROM customer c
JOIN customer_address_view v ON c.customer_id = v.customer_id;
Join với function
EXPLAIN ANALYZE
SELECT c.customer_id, c.first_name, c.last_name, f.address
FROM customer c
JOIN get_customers_with_address() f ON c.customer_id = f.customer_id;
Tại sao function lại nhanh hơn 2 cái còn lại?
Điểm khác biệt nằm ở đây:
Về bản chất thì view và native query thì y như nhau, nên ta sẽ so sánh view với function
Dưới đây là một số yếu tố quan trọng dẫn đến sự khác biệt về thời gian thực thi:
Còn query native thì cũng tuơng tự, nên không cần bàn
Vậy nếu sử dụng materizlize view thì sao?
Có thể thấy matetialize view cho thời gian thực thi nhanh nhất, bởi vì đơn giản nó tạo và gom sẵn các trường của nhiều bảng khác vào chung một bảng vật lý, nên khi query nó không cần phải join gì cả.
5. So sánh cùng 1 query có group by, where so sánh giữa dùng query native, view, function
Test trên tập nhỏ
Native query:
-- native query EXPLAIN ANALYZE SELECT co.country, COUNT(c.customer_id) FROM customer c JOIN address a ON c.address_id = a.address_id JOIN city ci ON a.city_id = ci.city_id JOIN country co ON ci.country_id = co.country_id WHERE co.country = 'USA' GROUP BY co.country;
View query
Function query
Test trên tập lớn
Native query:
-- native query
EXPLAIN ANALYZE
SELECT co.country, COUNT(c.customer_id)
FROM customer c
JOIN address a ON c.address_id = a.address_id
JOIN city ci ON a.city_id = ci.city_id
JOIN country co ON ci.country_id = co.country_id
WHERE co.country = 'USA'
GROUP BY co.country;
View query
Function query
Vậy còn materialize view, không cần phải nói chắc chắn nó sẽ là cái nhanh nhất:
Tổng kết:
Gợi ý dựa trên chuyên mục, nội dung tương tự và bài viết được độc giả quan tâm nhất