सरल DB संरचना (एक ऑनलाइन मंच के लिए):
CREATE TABLE users (
id integer NOT NULL PRIMARY KEY,
username text
);
CREATE INDEX ON users (username);
CREATE TABLE posts (
id integer NOT NULL PRIMARY KEY,
thread_id integer NOT NULL REFERENCES threads (id),
user_id integer NOT NULL REFERENCES users (id),
date timestamp without time zone NOT NULL,
content text
);
CREATE INDEX ON posts (thread_id);
CREATE INDEX ON posts (user_id);
तालिकाओं में लगभग 80k प्रविष्टियाँ users
और 2,6 मिलियन प्रविष्टियाँ posts
। शीर्ष 100 उपयोगकर्ताओं को उनके पोस्ट द्वारा प्राप्त करने के लिए इस सरल क्वेरी को 2,4 सेकंड लगते हैं :
EXPLAIN ANALYZE SELECT u.id, u.username, COUNT(p.id) AS PostCount FROM users u
INNER JOIN posts p on p.user_id = u.id
WHERE u.username IS NOT NULL
GROUP BY u.id
ORDER BY PostCount DESC LIMIT 100;
Limit (cost=316926.14..316926.39 rows=100 width=20) (actual time=2326.812..2326.830 rows=100 loops=1)
-> Sort (cost=316926.14..317014.83 rows=35476 width=20) (actual time=2326.809..2326.820 rows=100 loops=1)
Sort Key: (count(p.id)) DESC
Sort Method: top-N heapsort Memory: 32kB
-> HashAggregate (cost=315215.51..315570.27 rows=35476 width=20) (actual time=2311.296..2321.739 rows=34608 loops=1)
Group Key: u.id
-> Hash Join (cost=1176.89..308201.88 rows=1402727 width=16) (actual time=16.538..1784.546 rows=1910831 loops=1)
Hash Cond: (p.user_id = u.id)
-> Seq Scan on posts p (cost=0.00..286185.34 rows=1816634 width=8) (actual time=0.103..1144.681 rows=2173916 loops=1)
-> Hash (cost=733.44..733.44 rows=35476 width=12) (actual time=15.763..15.763 rows=34609 loops=1)
Buckets: 65536 Batches: 1 Memory Usage: 2021kB
-> Seq Scan on users u (cost=0.00..733.44 rows=35476 width=12) (actual time=0.033..6.521 rows=34609 loops=1)
Filter: (username IS NOT NULL)
Rows Removed by Filter: 11335
Execution time: 2301.357 ms
और set enable_seqscan = false
भी बदतर के साथ :
Limit (cost=1160881.74..1160881.99 rows=100 width=20) (actual time=2758.086..2758.107 rows=100 loops=1)
-> Sort (cost=1160881.74..1160970.43 rows=35476 width=20) (actual time=2758.084..2758.098 rows=100 loops=1)
Sort Key: (count(p.id)) DESC
Sort Method: top-N heapsort Memory: 32kB
-> GroupAggregate (cost=0.79..1159525.87 rows=35476 width=20) (actual time=0.095..2749.859 rows=34608 loops=1)
Group Key: u.id
-> Merge Join (cost=0.79..1152157.48 rows=1402727 width=16) (actual time=0.036..2537.064 rows=1910831 loops=1)
Merge Cond: (u.id = p.user_id)
-> Index Scan using users_pkey on users u (cost=0.29..2404.83 rows=35476 width=12) (actual time=0.016..41.163 rows=34609 loops=1)
Filter: (username IS NOT NULL)
Rows Removed by Filter: 11335
-> Index Scan using posts_user_id_index on posts p (cost=0.43..1131472.19 rows=1816634 width=8) (actual time=0.012..2191.856 rows=2173916 loops=1)
Planning time: 1.281 ms
Execution time: 2758.187 ms
username
Postgres में समूह गायब है, क्योंकि इसकी आवश्यकता नहीं है (SQL सर्वर का कहना है कि username
यदि मुझे उपयोगकर्ता नाम चुनना है तो मुझे समूह में आना होगा)। username
Postgres पर निष्पादन समय के लिए समूह के साथ थोड़ा सा ms जोड़ता है या कुछ नहीं करता है।
विज्ञान के लिए, मैंने Microsoft SQL सर्वर को उसी सर्वर पर स्थापित किया है (जो कि आर्कलीनक्स, 8 कोर xeon, 24 gb ram, ssd) चलाता है और Postgres के सभी डेटा - उसी तालिका संरचना, समान सूचक, समान डेटा को माइग्रेट करता है। 0,3 सेकंड में शीर्ष 100 पोस्टर चलाने के लिए समान क्वेरी :
SELECT TOP 100 u.id, u.username, COUNT(p.id) AS PostCount FROM dbo.users u
INNER JOIN dbo.posts p on p.user_id = u.id
WHERE u.username IS NOT NULL
GROUP BY u.id, u.username
ORDER BY PostCount DESC
पैदावार एक ही एक ही डेटा से परिणाम है, लेकिन 8 गुना तेजी से होता है। और यह लिनक्स पर एमएस एसक्यूएल का बीटा संस्करण है, मुझे लगता है कि यह "होम" ओएस - विंडोज सर्वर पर चल रहा है - यह अभी भी तेज हो सकता है।
क्या मेरी PostgreSQL क्वेरी पूरी तरह से गलत है, या अभी PostgreSQL धीमा है?
अतिरिक्त जानकारी
संस्करण लगभग नवीनतम है (9.6.1, वर्तमान में नवीनतम 9.6.2 है, ArchLinux में अभी पुराने पैकेज हैं और अद्यतन करने के लिए बहुत धीमा है)। कॉन्फ़िग:
max_connections = 75
shared_buffers = 3584MB
effective_cache_size = 10752MB
work_mem = 24466kB
maintenance_work_mem = 896MB
dynamic_shared_memory_type = posix
min_wal_size = 1GB
max_wal_size = 2GB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
EXPLAIN ANALYZE
आउटपुट: https://pastebin.com/HxucRgnk
सभी इंडेक्सों की कोशिश की, यहां तक कि GIN और GIST का उपयोग किया, PostgreSQL के लिए सबसे तेज़ तरीका (और कई पंक्तियों के साथ Googling पुष्टि करता है) अनुक्रमिक स्कैन का उपयोग करना है।
MS SQL सर्वर 14.0.405.200-1, डिफ़ॉल्ट कॉन्फिडेंस।
मैं एक एपीआई (विश्लेषण के बिना सादे चयन के साथ) में इसका उपयोग करता हूं, और क्रोम के साथ इस एपीआई एंडपॉइंट को कॉल करते हुए कहता है कि यह 2500 एमएस + लेता है, 50 एमबी एचटीटीपी और वेब सर्वर ओवरहेड ओवरहेड (एपीआई और एसक्यूएल रन एक ही सर्वर पर) जोड़ें - यह ऐसा ही है। मुझे यहां या वहां 100 एमएस की परवाह नहीं है, मुझे जो भी परवाह है वह दो पूरे सेकंड है।
explain analyze SELECT user_id, count(9) FROM posts group by user_id;
700 एमएस लेता है। posts
तालिका का आकार 2154 एमबी है।
GROUP BY u.id
यह करने के लिए GROUP BY p.user_id
और कहा कि कोशिश? मेरा अनुमान है, कि Postgres पहले और समूह में दूसरे से जुड़ता है क्योंकि आप उपयोगकर्ता तालिका पहचानकर्ता द्वारा समूहीकरण कर रहे हैं, भले ही आपको शीर्ष N - पंक्तियाँ प्राप्त करने के लिए केवल user_id की आवश्यकता हो।
posts
टेबल के बाकी हिस्सों से अलग करने का कोई मतलब हो ,CREATE TABLE post_content (post_id PRIMARY KEY REFERENCES posts (id), content text);
इस तरह की तालिका का उपयोग करते हुए, इस तरह के प्रश्नों पर 'बर्बाद' होने वाले अधिकांश I / O को बख्शा जा सकता है। पदों यह एक तुलना में छोटे होते हैंVACUUM FULL
परposts
कर सकते हैं मदद करते हैं।