मैं निम्न तालिकाओं है:मैं अपने पोस्टग्रेस चयन कथन की गति कैसे बढ़ा सकता हूं?
CREATE TABLE views (
view_id bigint NOT NULL,
usr_id bigint,
ip inet,
referer_id bigint,
country_id integer,
validated smallint,
completed smallint,
value numeric
);
ALTER TABLE ONLY views
ADD CONSTRAINT "Views_pkey" PRIMARY KEY (view_id);
CREATE TABLE country (
country_id integer NOT NULL,
country character varying(2)
);
ALTER TABLE ONLY country
ADD CONSTRAINT country_pkey PRIMARY KEY (country_id);
CREATE TABLE file_id_view_id (
file_id bigint,
view_id bigint,
created_ts timestamp without time zone
);
CREATE TABLE file_owner (
file_id bigint NOT NULL,
owner_id bigint
);
ALTER TABLE ONLY file_owner
ADD CONSTRAINT owner_table_pkey PRIMARY KEY (file_id);
CREATE TABLE referer (
referer_id bigint NOT NULL,
referer character varying(255)
);
ALTER TABLE ONLY referer
ADD CONSTRAINT referer_pkey PRIMARY KEY (referer_id);
views
और file_id_view_id
तालिका लगभग 340m पंक्तियों प्रत्येक है। प्रत्येक घंटे वे दोनों 600K पंक्तियों में वृद्धि करेंगे।
file_owner
तालिका 75K पंक्तियां हैं और पंक्तियों से प्रति घंटा की वृद्धि होगी।
country
तालिका में पंक्तियां और शायद ही कभी परिवर्तन होते हैं।
referer
तालिका में पंक्तियां और शायद ही कभी परिवर्तन होते हैं।
SELECT Count(ft.*) AS total_views,
(Count(ft.*) - SUM(ft.valid)) AS invalid_views,
SUM(ft.valid) AS valid_views,
SUM(ft.values) AS VALUES,
ft.day AS day,
(CASE
WHEN r.referer IS NULL THEN 'Unknown'
ELSE r.referer
END) AS referer,
(CASE
WHEN c.country IS NULL THEN 'Unknown'
ELSE c.country
END) AS country
FROM country c
right join (referer r
right join (SELECT v.validated AS valid,
v.value AS VALUES,
vf.day AS day,
vf.view_id AS view_id,
v.referer_id AS referer_id,
v.country_id AS country_id
FROM VIEWS v,
(SELECT view_id,
fivi.created_ts :: timestamp :: DATE AS
day
FROM file_id_view_id fivi
join (SELECT file_id
FROM file_owner
WHERE owner_id = 75
GROUP BY file_id) fo
ON (fo.file_id = fivi.file_id)
WHERE (fivi.created_ts BETWEEN
'2015-11-01' AND '2015-12-01')
GROUP BY view_id,
day) vf
WHERE v.view_id = vf.view_id) ft
ON (ft.referer_id = r.referer_id))
ON (ft.country_id = c.country_id)
GROUP BY day,
referer,
country;
उत्पादन करने के लिए:
मेरा लक्ष्य जैसे एक प्रश्न प्रदर्शन करने के लिए सक्षम होने के लिए है
total_views | invalid_views | valid_views | values | day | referer | country
------------+---------------+-------------+--------+------------+-----------------+---------
जब EXPLAIN ANALYZE
के साथ इस तरह क्वेरी चलाने निम्नलिखित उत्पादन किया जाता है:
GroupAggregate (cost=38893491.99..40443007.61 rows=182295955 width=52) (actual time=183725.696..205882.889 rows=172 loops=1)
Group Key: ((fivi.created_ts)::date), r.referer, c.country
-> Sort (cost=38893491.99..38984639.97 rows=182295955 width=52) (actual time=183725.655..200899.098 rows=8390217 loops=1)
Sort Key: ((fivi.created_ts)::date), r.referer, c.country
Sort Method: external merge Disk: 420192kB
-> Hash Left Join (cost=16340128.88..24989809.75 rows=182295955 width=52) (actual time=23399.900..104337.332 rows=8390217 loops=1)
Hash Cond: (v.country_id = c.country_id)
-> Hash Left Join (cost=16340125.36..24800637.72 rows=182295955 width=49) (actual time=23399.782..102534.655 rows=8390217 loops=1)
Hash Cond: (v.referer_id = r.referer_id)
-> Merge Join (cost=16340033.52..24051874.62 rows=182295955 width=29) (actual time=23397.410..99955.000 rows=8390217 loops=1)
Merge Cond: (fivi.view_id = v.view_id)
-> Group (cost=16340033.41..16716038.36 rows=182295955 width=16) (actual time=23397.298..30454.444 rows=8390217 loops=1)
Group Key: fivi.view_id, ((fivi.created_ts)::date)
-> Sort (cost=16340033.41..16434985.73 rows=189904653 width=16) (actual time=23397.294..28165.729 rows=8390217 loops=1)
Sort Key: fivi.view_id, ((fivi.created_ts)::date)
Sort Method: external merge Disk: 180392kB
-> Nested Loop (cost=6530.43..8799350.01 rows=189904653 width=16) (actual time=63.123..15131.956 rows=8390217 loops=1)
-> HashAggregate (cost=6530.31..6659.62 rows=43104 width=8) (actual time=62.983..90.331 rows=43887 loops=1)
Group Key: file_owner.file_id
-> Bitmap Heap Scan on file_owner (cost=342.90..6508.76 rows=43104 width=8) (actual time=5.407..50.779 rows=43887 loops=1)
Recheck Cond: (owner_id = 75)
Heap Blocks: exact=5904
-> Bitmap Index Scan on owner_id_index (cost=0.00..340.74 rows=43104 width=0) (actual time=4.327..4.327 rows=45576 loops=1)
Index Cond: (owner_id = 75)
-> Index Scan using file_id_view_id_indexing on file_id_view_id fivi (cost=0.11..188.56 rows=4406 width=24) (actual time=0.122..0.306 rows=191 loops=43887)
Index Cond: (file_id = file_owner.file_id)
Filter: ((created_ts >= '2015-11-01 00:00:00'::timestamp without time zone) AND (created_ts <= '2015-12-01 00:00:00'::timestamp without time zone))
Rows Removed by Filter: 184
-> Index Scan using "Views_pkey" on views v (cost=0.11..5981433.17 rows=338958763 width=25) (actual time=0.088..46804.757 rows=213018702 loops=1)
-> Hash (cost=68.77..68.77 rows=6591 width=28) (actual time=2.344..2.344 rows=6495 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 410kB
-> Seq Scan on referer r (cost=0.00..68.77 rows=6591 width=28) (actual time=0.006..1.156 rows=6495 loops=1)
-> Hash (cost=2.70..2.70 rows=233 width=7) (actual time=0.078..0.078 rows=233 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 10kB
-> Seq Scan on country c (cost=0.00..2.70 rows=233 width=7) (actual time=0.005..0.042 rows=233 loops=1)
Planning time: 1.015 ms
Execution time: 206034.660 ms
(37 rows)
व्याख्या पर योजना.depesz.com: http://explain.depesz.com/s/OiN
206s रन टाइम।
कुछ बातों का ध्यान रखना,
Postgresql संस्करण 9,4
मैं config समायोजित किया है इस प्रकार है:
- shared_buffers = 30GB
- work_mem = 32MB
- random_page_cost = 2.0
- cpu_tuple_cost = 0.0030
- cpu_index_tuple_cost = 0.0010
- cpu_operator_cost = 0।0005
- effective_cache_size = 52GB
निम्नलिखित अनुक्रमित वर्तमान में मौजूद:
- BTREE (देश) का उपयोग करते हुए देश सूचकांक country_index;
- INDEX बनाया_ts_index फ़ाइल_id_view_id पर btree (made_ts) का उपयोग करना;
- INDEX फ़ाइल_id_created_ts_index बनाएं file_id_view_id btree (create_ts, file_id) का उपयोग करना;
- INDEX फ़ाइल_id_view_id_indexing बनाएं file_id_view_id btree (file_id) का उपयोग करना;
- INDEX स्वामी_id_file_id_index बनाएं file_owner पर btree (file_id, owner_id) का उपयोग करना;
- INDEX owner_id_index बनाएं file_owner पर btree (owner_id) का उपयोग करना;
- बीटीआरई (रेफरर) का उपयोग करने वाले रेफरर पर INDEX referer_index बनाएं;
पूर्व क्वेरी एक स्वामी आईडी जो परंपरागत ढंग से चुना गया था उपयोग कर रहा था, कुछ क्वेरी परिणाम हो सकता है में 1/3 file_id_view_id तालिका केविचारों साथ जोड़ा जा सकेगा।
डेटा संरचना बदलना अंतिम रिज़ॉर्ट है। इस स्तर पर इस तरह के बदलाव गंभीर चिंताओं के कारण होना चाहिए।
डाटाबेस के रूप में केवल पढ़ने के लिए अगर, डेटा लिखा जा रहा करने की जरुरत घंटे के हिसाब और साँस लेने के कमरे के बहुत सारे पर किया जाता है प्रत्येक लिखने के बाद Postgres को दिया जाता है माना जा सकता है। वर्तमान समय में 600K प्रति घंटा के दौरान डीबी 1100 में लौट रहा है (यह सम्मिलित लागत के साथ अन्य कारणों के कारण है)। अतिरिक्त इंडेक्स जोड़ने के लिए बहुत सारे कमरे हैं यदि यह पढ़ने की गति को बढ़ाएगा, तो पढ़ने की गति प्राथमिकता है।
हार्डवेयर विनिर्देशों हैं:
सीपीयू: http://ark.intel.com/products/83356/Intel-Xeon-Processor-E5-2630-v3-20M-Cache-2_40-GHz
रैम: 128GB
भंडारण: 1.5TB PCIe SSD
मैं या तो मेरे डेटाबेस या क्वेरी कैसे अनुकूलन कर सकते हैं ताकि मैं उचित समय सीमा में डीबी से बाहर की जाने वाली जानकारी को पुनर्प्राप्त कर सकूं?
मुझे अपने वर्तमान डिजाइन अनुकूलन करने के लिए कर सकते हैं?
मैं Postgres विश्वास करते हैं और हार्डवेयर इस पर चल रहा है क्षमता ज्यादा बेहतर की तुलना में यह वर्तमान में है प्रदर्शन करने के लिए है।
अद्यतन
मैं कोशिश की है:
- तालिकाओं का विश्लेषण करें, प्रदर्शन प्रभावित नहीं किया।
- work_mem बढ़ाएं, इसके परिणामस्वरूप गति में 116 की वृद्धि हुई है।
- उप-चयनों से परहेज करके पोस्टग्रेस के प्रश्न योजनाकार पर निर्भर करता है, यह नकारात्मक प्रभाव प्रदर्शन।
- हाथ से अलग डीबी लुकअप, यह प्रतीत होता है कि कोई सकारात्मक/नकारात्मक प्रभाव नहीं है।
क्या किसी के पास कोई बड़ा अनुभव पुनर्गठन सारणी है? क्या यह व्यवहार्य है? क्या इसमें दिन लगेंगे, घंटे (कोर्स का अनुमान)?
मैं डेटाबेस को डी-सामान्य करने पर विचार कर रहा हूं, क्योंकि इसे वास्तव में केवल इस विधि में संदर्भित किया जाएगा। इसके साथ मेरी एकमात्र चिंता यह है कि - यदि किसी इंडेक्स किए गए मालिक_आईडी के साथ एक टेबल से 100 एम पंक्तियों को बुलाया जाना चाहिए, तो यह पर्याप्त तेज़ होगा या फिर भी मुझे एक ही प्रदर्शन के मुद्दों का सामना करना पड़ेगा? एक तरफ जाने से नफरत होगी तो पीछे हटना होगा।
मैं जिस अन्य समाधान में देख रहा हूं वह @ ivan.panasuik सुझाव है, पूरे दिन डेटा को किसी अन्य तालिका में समूहित करें क्योंकि एक बार दिन बीत चुका है कि जानकारी स्थिर है और इसे बदलने या अपडेट करने की आवश्यकता नहीं है। हालांकि मुझे यह सुनिश्चित नहीं है कि इसे आसानी से कैसे कार्यान्वित किया जाए - क्या मुझे डेटा के माध्यम से पूछताछ होनी चाहिए, जबकि आवेषण होल्ड हो और जितनी जल्दी संभव हो सके दिन पकड़ लें? तब से एक ट्रिगर सेट है?
अनुमान वास्तव में सटीक नहीं हैं।क्या आपने शामिल तालिकाओं का विश्लेषण किया था? आपके पास डिस्क पर किए गए दो बहुत बड़े प्रकार भी हैं। आप work_mem को उस क्वेरी_ के लिए भारी रूप से बढ़ाने की कोशिश कर सकते हैं, उदा। 'work_mem =' 512MB 'सेट करें या यहां तक कि' work_mem = '1GB'' –
मैं इंप्रेशन के तहत था पोस्टग्रेस स्वचालित रूप से टेबल का विश्लेषण करेगा, क्या मुझे इसे मैन्युअल रूप से भी करना चाहिए? जब आप _that query_ कहते हैं, तो क्या आपका मतलब है कि एक ही क्वेरी के लिए work_mem सेट करने का एक विशिष्ट तरीका है? –
यह _should_ स्वचालित रूप से ऐसा करता है, लेकिन कभी-कभी (जैसे प्रारंभिक लोड के बाद) यह पर्याप्त तेज़ नहीं होता है। आपके द्वारा दिखाए जाने वाले बयान _before_ आपकी क्वेरी को चालू सत्र के लिए 'work_mem' बदल देंगे: http://www.postgresql.org/docs/current/static/sql-set.html –