2012-12-04 21 views
7

ऑप्टिमाइज़ करें मेरे पास पोस्टग्रेएसक्यूएल 9.1 में 2 टेबल हैं - flight_2012_09_12 जिसमें लगभग 500,000 पंक्तियां और स्थिति_2012_09_12 हैं जिनमें लगभग 5.5 मिलियन पंक्तियां हैं। मैं एक साधारण जॉइन क्वेरी चला रहा हूं और इसे पूरा करने में काफी समय लग रहा है और इस तथ्य के बावजूद कि टेबल छोटे नहीं हैं, मुझे विश्वास है कि निष्पादन में कुछ प्रमुख लाभ किए जा सकते हैं।पोस्टग्रेस्क्ल क्वेरी

क्वेरी है:

SELECT f.departure, f.arrival, 
     p.callsign, p.flightkey, p.time, p.lat, p.lon, p.altitude_ft, p.speed 
FROM position_2012_09_12 AS p 
JOIN flight_2012_09_12 AS f 
    ON p.flightkey = f.flightkey 
WHERE p.lon < 0 
     AND p.time BETWEEN '2012-9-12 0:0:0' AND '2012-9-12 23:0:0' 

समझाने का विश्लेषण के उत्पादन में है:

Hash Join (cost=239891.03..470396.82 rows=4790498 width=51) (actual time=29203.830..45777.193 rows=4403717 loops=1) 
Hash Cond: (f.flightkey = p.flightkey) 
-> Seq Scan on flight_2012_09_12 f (cost=0.00..1934.31 rows=70631 width=12) (actual time=0.014..220.494 rows=70631 loops=1) 
-> Hash (cost=158415.97..158415.97 rows=3916885 width=43) (actual time=29201.012..29201.012 rows=3950815 loops=1) 
    Buckets: 2048 Batches: 512 (originally 256) Memory Usage: 1025kB 
    -> Seq Scan on position_2012_09_12 p (cost=0.00..158415.97 rows=3916885 width=43) (actual time=0.006..14630.058 rows=3950815 loops=1) 
      Filter: ((lon < 0::double precision) AND ("time" >= '2012-09-12 00:00:00'::timestamp without time zone) AND ("time" <= '2012-09-12 23:00:00'::timestamp without time zone)) 
Total runtime: 58522.767 ms 

मुझे लगता है कि समस्या स्थिति मेज पर अनुक्रमिक स्कैन के साथ निहित है, लेकिन मैं बाहर क्यों समझ नहीं सकता यह वहाँ है। सूचकांक तालिका संरचनाओं में नीचे हैं:

   Table "public.flight_2012_09_12" 
    Column  |   Type    | Modifiers 
--------------------+-----------------------------+----------- 
callsign   | character varying(8)  | 
flightkey   | integer      | 
source    | character varying(16)  | 
departure   | character varying(4)  | 
arrival   | character varying(4)  | 
original_etd  | timestamp without time zone | 
original_eta  | timestamp without time zone | 
enroute   | boolean      | 
etd    | timestamp without time zone | 
eta    | timestamp without time zone | 
equipment   | character varying(6)  | 
diverted   | timestamp without time zone | 
time    | timestamp without time zone | 
lat    | double precision   | 
lon    | double precision   | 
altitude   | character varying(7)  | 
altitude_ft  | integer      | 
speed    | character varying(4)  | 
asdi_acid   | character varying(4)  | 
enroute_eta  | timestamp without time zone | 
enroute_eta_source | character varying(1)  | 
Indexes: 
"flight_2012_09_12_flightkey_idx" btree (flightkey) 
"idx_2012_09_12_altitude_ft" btree (altitude_ft) 
"idx_2012_09_12_arrival" btree (arrival) 
"idx_2012_09_12_callsign" btree (callsign) 
"idx_2012_09_12_departure" btree (departure) 
"idx_2012_09_12_diverted" btree (diverted) 
"idx_2012_09_12_enroute_eta" btree (enroute_eta) 
"idx_2012_09_12_equipment" btree (equipment) 
"idx_2012_09_12_etd" btree (etd) 
"idx_2012_09_12_lat" btree (lat) 
"idx_2012_09_12_lon" btree (lon) 
"idx_2012_09_12_original_eta" btree (original_eta) 
"idx_2012_09_12_original_etd" btree (original_etd) 
"idx_2012_09_12_speed" btree (speed) 
"idx_2012_09_12_time" btree ("time") 

      Table "public.position_2012_09_12" 
Column |   Type    | Modifiers 
-------------+-----------------------------+----------- 
callsign | character varying(8)  | 
flightkey | integer      | 
time  | timestamp without time zone | 
lat   | double precision   | 
lon   | double precision   | 
altitude | character varying(7)  | 
altitude_ft | integer      | 
course  | integer      | 
speed  | character varying(4)  | 
trackerkey | integer      | 
the_geom | geometry     | 
Indexes: 
"index_2012_09_12_altitude_ft" btree (altitude_ft) 
"index_2012_09_12_callsign" btree (callsign) 
"index_2012_09_12_course" btree (course) 
"index_2012_09_12_flightkey" btree (flightkey) 
"index_2012_09_12_speed" btree (speed) 
"index_2012_09_12_time" btree ("time") 
"position_2012_09_12_flightkey_idx" btree (flightkey) 
"test_index" btree (lon) 
"test_index_lat" btree (lat) 

मैं किसी अन्य तरीके से क्वेरी के पुनर्लेखन के लिए और इसलिए मैं इस बिंदु पर स्टम्प्ड रहा हूँ के बारे में सोच नहीं कर सकते। यदि वर्तमान सेटअप उतना अच्छा है जितना ऐसा हो जाता है लेकिन ऐसा लगता है कि यह वर्तमान में उससे कहीं अधिक तेज़ होना चाहिए। कोई भी सहायताकाफी प्रशंसनीय होगी।

+0

क्या आप public.position_2012_09_12 टेबल लॉन और समय कॉलम पर आंकड़े प्रदान कर सकते हैं? हो सकता है कि कुछ (समय) जहां लोन <0 इंडेक्स मदद करेगा लेकिन स्थिति तालिका में 3950815 पंक्तियां हैं जो इस परिस्थितियों से मेल खाते हैं। क्या इस टेबल में बहुत अधिक डेटा है? – sufleR

+0

उस तालिका में 5563070 पंक्तियां हैं (मेरी पोस्ट को संपादित करने के लिए संपादित किया गया है कि मूल रूप से 3.5 मिलियन के बारे में बताया गया है) – TheOx

+2

पोस्टग्रेस्क्ल का कौन सा संस्करण आप उपयोग कर रहे हैं? – plang

उत्तर

2

आपको अनुक्रमिक स्कैन प्राप्त करने का कारण यह है कि पोस्टग्रेस का मानना ​​है कि यह इंडेक्स का उपयोग करने से कम डिस्क पेजों को पढ़ेगा। यह शायद सही है। विचार करें, यदि आप गैर-कवरिंग इंडेक्स का उपयोग करते हैं, तो आपको सभी मिलान करने वाले इंडेक्स पृष्ठों को पढ़ने की आवश्यकता है। यह अनिवार्य रूप से पंक्ति पहचानकर्ताओं की एक सूची आउटपुट करता है। डीबी इंजन को तब मिलान करने वाले प्रत्येक डेटा पेज को पढ़ने की जरूरत है।

आपकी स्थिति तालिका प्रति पंक्ति 71 बाइट्स का उपयोग करती है, साथ ही जो भी भूगर्भ प्रकार लेता है (मैं चित्रण के लिए 16 बाइट्स मानता हूं), 87 बाइट बना देता है। एक पोस्टग्रेस पेज 8192 बाइट्स है। तो आपके पास प्रति पृष्ठ लगभग 9 0 पंक्तियां हैं।

आपकी क्वेरी 5563070 पंक्तियों में से कुल 3950815 से मेल खाती है, या कुल में से लगभग 70%।डेटा को मानते हुए, आपके फ़िल्टर के संबंध में, यादृच्छिक रूप से वितरित किया जाता है, कोई मिलान पंक्ति वाले डेटा पृष्ठ को खोजने का 30%^9 0 मौका बहुत अधिक है। यह अनिवार्य रूप से कुछ भी नहीं है। तो इस पर ध्यान दिए बिना कि आपकी अनुक्रमणिका कितनी अच्छी है, आपको अभी भी सभी डेटा पेजों को पढ़ना होगा। यदि आपको वैसे भी सभी पृष्ठों को पढ़ना होगा, तो टेबल स्कैन आमतौर पर एक अच्छा दृष्टिकोण है।

कोई यहां बाहर निकलता है, यह है कि मैंने गैर-कवरिंग इंडेक्स कहा। यदि आप इंडेक्स बनाने के लिए तैयार हैं जो स्वयं के प्रश्नों का उत्तर दे सकते हैं, तो आप डेटा पेजों को देखने से बच सकते हैं, इसलिए आप गेम में वापस आ गए हैं। मेरा सुझाव है कि निम्नलिखित देखने योग्य हैं:

flight_2012_09_12 (flightkey, departure, arrival) 
position_2012_09_12 (filghtkey, time, lon, ...) 
position_2012_09_12 (lon, time, flightkey, ...) 
position_2012_09_12 (time, long, flightkey, ...) 

यहां दिए गए कॉलम आपके द्वारा चुने गए शेष कॉलम का प्रतिनिधित्व करते हैं। आपको केवल स्थिति में इंडेक्स की आवश्यकता होगी, लेकिन यह कहना मुश्किल है कि कौन सा सर्वश्रेष्ठ साबित होगा। पहला दृष्टिकोण फिल्टरिंग करने के लिए पूरे दूसरे इंडेक्स को पढ़ने की लागत के साथ, पूर्ववर्ती डेटा पर विलय में शामिल होने की अनुमति दे सकता है। दूसरा और तीसरा डेटा को प्रीफिल्टर करने की अनुमति देगा, लेकिन हैश में शामिल होने की आवश्यकता है। हैश में शामिल होने की लागत कितनी है, विलय में शामिल होना अच्छा विकल्प हो सकता है।

आपकी क्वेरी के लिए प्रति पंक्ति 87 बाइट्स 52 की आवश्यकता होती है, और इंडेक्स के ऊपर की ओर बढ़ने की आवश्यकता होती है, तो आप इंडेक्स के साथ अधिक नहीं ले सकते हैं, यदि कोई हो, तो टेबल को कम जगह पर ले जाएं।

क्लस्टरिंग को देखकर, "यादृच्छिक रूप से वितरित" पक्ष पर हमला करना एक और तरीका है।

+1

यह मुझे नहीं देखा कि उड़ान तालिका पर एक कवरिंग इंडेक्स जोड़ने के लायक होगा, क्योंकि एक पूर्ण स्कैन केवल 220ms लेता है? –

+0

@ डेविड एल्ड्रिज फेयर प्वाइंट, हालांकि दोनों टेबलों पर फ्लाइट कुंजी से शुरू होने वाली कवरिंग इंडेक्स में विलय में शामिल होने की इजाजत हो सकती है, जिसे मैं पूर्व-क्रमबद्ध डेटा पर हैश से जुड़ने की अपेक्षा करता हूं। – Laurence

+0

@ डेविड एल्ड्रिज उपयोगकर्ता पोस्टग्रेएसक्यूएल 9.1 पर है, जिसमें इंडेक्स-केवल स्कैन नहीं हैं (जैसे इंडेक्स को कवर करना), इसलिए समस्या किसी भी तरह से चल रही है। –

3

पंक्ति गणना अनुमान बहुत उचित हैं, इसलिए मुझे संदेह है कि यह एक आंकड़े मुद्दा है।

मैं कोशिश करता हूँ:

  • यदि आप नियमित रूप से lon < 0 के लिए खोज position_2012_09_12("time") WHERE (lon < 0) पर position_2012_09_12(lon,"time") पर एक सूचकांक या संभवतः एक आंशिक सूचकांक बना रहा है।

  • random_page_cost कम, शायद 1.1 सेट करना। देखें कि (ए) यह योजना बदलता है और (बी) यदि नई योजना वास्तव में तेज़ है। परीक्षण उद्देश्यों के लिए यह देखने के लिए कि क्या एक सेक्स्केन से परहेज करना तेज होगा, आप SET enable_seqscan = off कर सकते हैं; यदि यह है, लागत पैरामीटर बदलें।

  • इस क्वेरी के लिए work_mem बढ़ाएं। SET work_mem = 10M या इसे चलाने से पहले कुछ।

  • नवीनतम पोस्टग्रेएसक्यूएल चलाना यदि आप पहले से नहीं हैं। प्रश्नों में हमेशा अपने PostgreSQL संस्करण निर्दिष्ट करें। (संपादन के बाद अद्यतन): आप 9.1 पर हैं; कोई बात नहीं। 9.2 में सबसे बड़ा प्रदर्शन सुधार सूचकांक-केवल स्कैन था, और ऐसा लगता है कि आपको इस क्वेरी के लिए केवल इंडेक्स-स्कैन से बड़े पैमाने पर लाभ नहीं होगा।

यदि आप पंक्तियों को संकीर्ण करने के लिए कॉलम से छुटकारा पा सकते हैं तो आप कुछ हद तक प्रदर्शन में सुधार करेंगे। इससे बहुत अंतर नहीं आएगा, लेकिन यह कुछ बना देगा।