মাপকাঠি
Postgres সঙ্গে সবচেয়ে আকর্ষণীয় প্রার্থীদের পরীক্ষা করা 9.4 এবং 9.5 একটি অর্ধেক বাস্তবসম্মত টেবিলের সাথে 200K সারি মধ্যে purchases
এবং 10k স্বতন্ত্রcustomer_id
( গড়। গ্রাহক প্রতি 20 সারি )।
পোস্টগ্রিস 9.5 এর জন্য আমি কার্যকরভাবে 86446 স্বতন্ত্র গ্রাহকদের সাথে একটি দ্বিতীয় পরীক্ষা চালিয়েছি। নীচে দেখুন ( প্রতি গ্রাহকের গড় 2.3 সারি )।
সেটআপ
প্রধান টেবিল
CREATE TABLE purchases (
id serial
, customer_id int -- REFERENCES customer
, total int -- could be amount of money in Cent
, some_column text -- to make the row bigger, more realistic
);
আমি একটি serial
(নীচে যুক্ত পিকে সীমাবদ্ধ) এবং একটি পূর্ণসংখ্যা ব্যবহার করি customer_id
কারণ এটি আরও সাধারণ সেটআপ। some_column
সাধারণত আরও কলামগুলির জন্য তৈরি করতে যুক্ত করা হয়।
ডামি ডেটা, পিকে, ইনডেক্স - একটি সাধারণ টেবিলটিতে কিছু মৃত টিপল থাকে:
INSERT INTO purchases (customer_id, total, some_column) -- insert 200k rows
SELECT (random() * 10000)::int AS customer_id -- 10k customers
, (random() * random() * 100000)::int AS total
, 'note: ' || repeat('x', (random()^2 * random() * random() * 500)::int)
FROM generate_series(1,200000) g;
ALTER TABLE purchases ADD CONSTRAINT purchases_id_pkey PRIMARY KEY (id);
DELETE FROM purchases WHERE random() > 0.9; -- some dead rows
INSERT INTO purchases (customer_id, total, some_column)
SELECT (random() * 10000)::int AS customer_id -- 10k customers
, (random() * random() * 100000)::int AS total
, 'note: ' || repeat('x', (random()^2 * random() * random() * 500)::int)
FROM generate_series(1,20000) g; -- add 20k to make it ~ 200k
CREATE INDEX purchases_3c_idx ON purchases (customer_id, total DESC, id);
VACUUM ANALYZE purchases;
customer
টেবিল - উচ্চতর প্রশ্নের জন্য
CREATE TABLE customer AS
SELECT customer_id, 'customer_' || customer_id AS customer
FROM purchases
GROUP BY 1
ORDER BY 1;
ALTER TABLE customer ADD CONSTRAINT customer_customer_id_pkey PRIMARY KEY (customer_id);
VACUUM ANALYZE customer;
9.5 এর জন্য আমার দ্বিতীয় পরীক্ষায় আমি একই সেটআপটি ব্যবহার করেছি, তবে প্রতি মাত্র কয়েকটি সারি পাওয়ার random() * 100000
জন্য উত্পন্ন করেছি ।customer_id
customer_id
টেবিলের জন্য বস্তুর আকার purchases
এই কোয়েরিটি দিয়ে তৈরি করা হয়েছে ।
what | bytes/ct | bytes_pretty | bytes_per_row
-----------------------------------+----------+--------------+---------------
core_relation_size | 20496384 | 20 MB | 102
visibility_map | 0 | 0 bytes | 0
free_space_map | 24576 | 24 kB | 0
table_size_incl_toast | 20529152 | 20 MB | 102
indexes_size | 10977280 | 10 MB | 54
total_size_incl_toast_and_indexes | 31506432 | 30 MB | 157
live_rows_in_text_representation | 13729802 | 13 MB | 68
------------------------------ | | |
row_count | 200045 | |
live_tuples | 200045 | |
dead_tuples | 19955 | |
ক্যোয়ারী
WITH cte AS (
SELECT id, customer_id, total
, row_number() OVER(PARTITION BY customer_id ORDER BY total DESC) AS rn
FROM purchases
)
SELECT id, customer_id, total
FROM cte
WHERE rn = 1;
২. row_number()
সাবকিউরিতে (আমার অনুকূলিতকরণ)
SELECT id, customer_id, total
FROM (
SELECT id, customer_id, total
, row_number() OVER(PARTITION BY customer_id ORDER BY total DESC) AS rn
FROM purchases
) sub
WHERE rn = 1;
SELECT DISTINCT ON (customer_id)
id, customer_id, total
FROM purchases
ORDER BY customer_id, total DESC, id;
৪. সাবটিয়ের সাথে LATERAL
আরসিটিই ( এখানে দেখুন )
WITH RECURSIVE cte AS (
( -- parentheses required
SELECT id, customer_id, total
FROM purchases
ORDER BY customer_id, total DESC
LIMIT 1
)
UNION ALL
SELECT u.*
FROM cte c
, LATERAL (
SELECT id, customer_id, total
FROM purchases
WHERE customer_id > c.customer_id -- lateral reference
ORDER BY customer_id, total DESC
LIMIT 1
) u
)
SELECT id, customer_id, total
FROM cte
ORDER BY customer_id;
5. সাথে customer
টেবিল LATERAL
( এখানে দেখুন )
SELECT l.*
FROM customer c
, LATERAL (
SELECT id, customer_id, total
FROM purchases
WHERE customer_id = c.customer_id -- lateral reference
ORDER BY total DESC
LIMIT 1
) l;
SELECT (array_agg(id ORDER BY total DESC))[1] AS id
, customer_id
, max(total) AS total
FROM purchases
GROUP BY customer_id;
ফলাফল
উপরোক্ত প্রশ্নের জন্য কার্যকর করার সময় EXPLAIN ANALYZE
(এবং সমস্ত বিকল্প বন্ধ রয়েছে ), সেরা 5 রান ।
সমস্ত ক্যোয়ারিতে সূচি স্ক্যান ব্যবহার করা হয়েছে purchases2_3c_idx
(অন্যান্য পদক্ষেপের মধ্যে) among এর মধ্যে কিছু কেবল সূচকের ছোট আকারের জন্য, অন্যরা আরও কার্যকরভাবে।
A. 200k সারি এবং প্রতি 20 ডলার দিয়ে 9.4 পোস্ট করে customer_id
1. 273.274 ms
2. 194.572 ms
3. 111.067 ms
4. 92.922 ms
5. 37.679 ms -- winner
6. 189.495 ms
বি। পোস্টগ্রিস 9.5 এর সাথে একই
1. 288.006 ms
2. 223.032 ms
3. 107.074 ms
4. 78.032 ms
5. 33.944 ms -- winner
6. 211.540 ms
সি। বি হিসাবে একই, তবে প্রতি ~ 2.3 সারি customer_id
1. 381.573 ms
2. 311.976 ms
3. 124.074 ms -- winner
4. 710.631 ms
5. 311.976 ms
6. 421.679 ms
সম্পর্কিত মানদণ্ড
পোস্টগ্রেস 11.5 (সেপ্টেম্বর, 2019- তে বর্তমান) তে 10 এম সারি এবং 60 কে অনন্য "গ্রাহক" দিয়ে "ওজিআর" পরীক্ষার মাধ্যমে এখানে একটি নতুন দেওয়া হয়েছে । ফলাফল আমরা এখনও পর্যন্ত যা দেখেছি তার সাথে সামঞ্জস্যপূর্ণ:
আসল (পুরানো) বেনমার্ক ২০১১ থেকে
আমি পোস্টগ্র্রেএসকিউএল 9.1 এর সাথে 65579 সারিগুলির একটি রিয়েল লাইফ টেবিল এবং তিনটি কলামের প্রত্যেকটিতে সিঙ্গল-কলাম বিটি্রি ইনডেক্সের সাথে তিনটি পরীক্ষা চালিয়েছি এবং 5 টির সেরা মৃত্যুদন্ড কার্যকর সময় নিয়েছি । @ ওএমজিপনিজের প্রথম ক্যোয়ারী ( ) উপরের সমাধানের সাথে
তুলনা করা ( ):A
DISTINCT ON
B
পুরো টেবিলটি নির্বাচন করুন, এক্ষেত্রে 5958 টি সারিতে ফলাফল।
A: 567.218 ms
B: 386.673 ms
WHERE customer BETWEEN x AND y
1000 সারি ফলে শর্ত ব্যবহার করুন ।
A: 249.136 ms
B: 55.111 ms
সাথে একটি একক গ্রাহক নির্বাচন করুন WHERE customer = x
।
A: 0.143 ms
B: 0.072 ms
অন্যান্য উত্তরে বর্ণিত সূচকের সাথে একই পরীক্ষার পুনরাবৃত্তি
CREATE INDEX purchases_3c_idx ON purchases (customer, total DESC, id);
1A: 277.953 ms
1B: 193.547 ms
2A: 249.796 ms -- special index not used
2B: 28.679 ms
3A: 0.120 ms
3B: 0.048 ms
MAX(total)
?