किसी एक तालिका के साथ या मल्टी-टेबल इंडेक्स के लाभों के बारे में मानचित्र बनाएं

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

एक परत के साथ काम करने के संदर्भ में, हम कम या ज्यादा पता लगाते हैं, लेकिन वास्तव में दर्जनों परतें हो सकती हैं, उनमें से प्रत्येक को स्थानिक सूचकांक में अनुरोध करना होगा, भले ही खोज सीमा में कुछ भी न मिला हो ... क्या यह किसी तरह संभव है इस प्रक्रिया को साफ करने और स्पष्ट रूप से बेकार कार्यों से छुटकारा पाने के लिए?

अनुक्रमण


यह संभव है, क्यों नहीं लेकिन इसके लिए हमें सभी स्थानिक परतों के लिए एकल स्थानिक सूचकांक बनाना होगा। याद करें कि हमारे सूचकांक किस प्रकार संरचित हैं:

ठीक है, एक एकल सूचकांक बनाने के लिए, आपको सभी परतों को एक ग्रिड के साथ विभाजित करना होगा, उसी तरह ब्लॉक को संख्या देना होगा, और ऑब्जेक्ट पहचानकर्ता के अलावा, तालिका पहचानकर्ता को भी सूचकांक में संग्रहीत करना होगा। तो:

सूचकांक के प्रदर्शन को मापें।


हम वर्ग में 10,000 यादृच्छिक खोजों की एक श्रृंखला चलाएंगे [35 ... 45.50 ... 60] ° सामान्य सूचकांक पर और पुराने तरीके से। सभी अनुरोधों को एक कनेक्शन में निष्पादित किया जाता है यानी एकल कोर पर प्रदर्शन दिखाएं।
अनुरोध का आकारएक ही सूचकांक में समयपुराना समय
0.01 ° है7'35 ''8'26 ''
0.1 °8'25 ''9'20 ''
0.5 °15'11 ''16'7 ''
निष्कर्ष : हां, एक एकल सूचकांक तेजी से काम करता है, लेकिन परिणाम आश्चर्यजनक नहीं है। दूसरी ओर, हमारी सभी 4 परतें अपेक्षाकृत घनी आबादी वाली हैं, फिर से यह महत्वपूर्ण है कि डेटा की मात्रा अपेक्षाकृत कम हो ताकि एकल खोज के सभी लाभों का पूरी तरह से विस्तार हो। तीसरी तरफ, यह लाइव डेटा है, जैसा कि यह है।

नक्शा खींचना


सबसे पहले, हम इसे पुराने तरीके से आकर्षित करेंगे, ताकि तुलना करने के लिए कुछ हो।
 create procedure mk_test_gif( in cminx double precision, in cminy double precision, in cmaxx double precision, in cmaxy double precision) { declare img any; img := img_create (512, 512, cminx, cminy, cmaxx, cmaxy, 1); declare cl integer; declare bg integer; { cl := img_alloc_color (img, 0, 0, 255); bg := img_alloc_color (img, 0, 0, 255); whenever not found goto nf; for select blob_to_string(Shape) as data from xxx.YYY."water-polygon" as x, xxx.YYY."v_water-polygon_spx_enum_items_in_box" as a where a.minx = cminx and a.miny = cminy and a.maxx = cmaxx and a.maxy = cmaxy and x."_OBJECTID_" = a.oid and x.maxx_ >= cminx and x.minx_ <= cmaxx and x.maxy_ >= cminy and x.miny_ <= cmaxy do { img_draw_polygone (img, data, cl, bg); } nf:; ...      ,    img_draw_polyline. ... } declare ptr integer; ptr := img_tostr (img); img_destroy (img); declare image any; image := img_fromptr(ptr); string_to_file('test.gif', image, -2); return; }; mk_test_gif(35., 50., 45., 60.); 
काम में 17.2 सेकंड लगते हैं।

अब, जैसा कि वादा किया गया था, एक चयन में। पहली बात जो दिमाग में आती है
एकत्र करता है
एक एग्रीगेट एक ऑब्जेक्ट है जो कर्सर को खोलने पर बनाया जाता है, परिणाम की प्रत्येक पंक्ति पर कॉल किया जाता है, और कर्सर बंद होने पर अंतिम रूप दिया जाता है।
 create function mapx_agg_init (inout _agg any) {;}; create function mapx_agg_acc ( inout _agg any, in _tab integer, in _oid integer ) { if (_agg is null) { declare img any; img := img_create (512, 512, _tab[0], _tab[1], _tab[2], _tab[3], 1); _agg := img; return 0; } else { return case when _tab = 4 then (img_draw_polygone(_agg, ( select blob_to_string(bl.Shape) from "xxx"."YYY"."building-polygon" as bl where bl."_OBJECTID_" = _oid), 255, 255)) when _tab = 3 then (img_draw_polyline(_agg, ( select blob_to_string(hw.Shape) from "xxx"."YYY"."highway-line" as hw where hw."_OBJECTID_" = _oid), 100, 100)) when _tab = 2 then (img_draw_polygone(_agg, ( select blob_to_string(vg.Shape) from "xxx"."YYY"."vegetation-polygon" as vg where vg."_OBJECTID_" = _oid), 10, 10)) when _tab = 1 then (img_draw_polygone(_agg, ( select blob_to_string(wt.Shape) from "xxx"."YYY"."water-polygon" as wt where wt."_OBJECTID_" = _oid), 50, 50)) else 1 end; } }; create function mapx_agg_final (inout _agg any) returns integer { declare ptr integer; ptr := img_tostr (_agg); img_destroy (_agg); declare image any; image := img_fromptr(ptr); string_to_file('nskx_ii.gif', image, -2); return 1; }; create aggregate mapx_agg (in _tab integer, in _oid integer) returns integer from mapx_agg_init, mapx_agg_acc, mapx_agg_final; create procedure mk_testx_ii_gif( in cminx double precision, in cminy double precision, in cmaxx double precision, in cmaxy double precision) { declare cnt integer; select mapx_agg(tab, oid) into cnt from ( select * from (select vector(cminx, cminy, cmaxx, cmaxy) as tab, 0 as oid) as f1 union all (select tab, oid from xxx.YYY."v_total__spx_enum_items_in_box" as a where a.minx = cminx and a.miny = cminy and a.maxx = cmaxx and a.maxy = cmaxy) ) f_all; } mk_testx_ii_gif(35., 50., 45., 60.); 
दुर्भाग्य से, एग्रीगेट पैरामीटर को एग्रीगेट में पास करने के लिए कोई नियमित तरीका नहीं है, इसलिए आपको ट्रिक पर जाना होगा, डेटा से यूनियन को स्लिप करना होगा और इनिशियलाइज़ेशन स्ट्रिंग को कंस्ट्रक्टर में नहीं, बल्कि जब आप पहली लाइन प्राप्त करते हैं, तो संदर्भ का निर्माण करें।
यह कैसे हो सकता है, एक चौकस पाठक कहेगा, एक चयनित का वादा किया गया था, और उनमें से एक पूरी गुच्छा है! वास्तव में, पंक्ति पहचानकर्ता एक क्रमबद्ध और सारणीबद्ध तरीके से समुच्चय में आते हैं, इसलिए स्पष्ट उपश्रेणियाँ वास्तव में हाथ मिलाकर आयोजित की जाती हैं।
तो, रन समय 42 सेकंड है। हाँ।

एक और प्रयास
 create procedure mk_testx_gif( in cminx double precision, in cminy double precision, in cmaxx double precision, in cmaxy double precision) { declare img any; img := img_create (512, 512, cminx, cminy, cmaxx, cmaxy, 1); declare cnt, cnt2 integer; declare cl1, bg1 integer; cl1 := img_alloc_color (img, 0, 0, 255); bg1 := img_alloc_color (img, 0, 0, 255); declare cl2, bg2 integer; cl2 := img_alloc_color (img, 0, 255, 0); bg2 := img_alloc_color (img, 0, 255, 0); declare cl3, bg3 integer; cl3 := img_alloc_color (img, 255, 100, 0); bg3 := img_alloc_color (img, 255, 100, 0); declare cl4, bg4 integer; cl4 := img_alloc_color (img, 255, 0, 0); bg4 := img_alloc_color (img, 255, 0, 0); select sum ( case when geom is null then 0 when geom_type = 2 then (img_draw_polyline(img, geom, cl, bg)) else (img_draw_polygone(img, geom, cl, bg)) end ) into cnt from ( select case when a.tab = 4 then ( select blob_to_string(bl.Shape) from "xxx"."YYY"."building-polygon" as bl where bl."_OBJECTID_" = a.oid) when a.tab = 3 then ( select blob_to_string(hw.Shape) from "xxx"."YYY"."highway-line" as hw where hw."_OBJECTID_" = a.oid) when a.tab = 2 then ( select blob_to_string(vg.Shape) from "xxx"."YYY"."vegetation-polygon" as vg where vg."_OBJECTID_" = a.oid) when a.tab = 1 then ( select blob_to_string(wt.Shape) from "xxx"."YYY"."water-polygon" as wt where wt."_OBJECTID_" = a.oid) else '' end as geom, case when a.tab = 3 then 2 else 1 end as geom_type, case when a.tab = 4 then cl4 when a.tab = 3 then cl3 when a.tab = 2 then cl2 when a.tab = 1 then cl1 else 0 end as cl, case when a.tab = 4 then bg4 when a.tab = 3 then bg3 when a.tab = 2 then bg2 when a.tab = 1 then bg1 else 0 end as bg from xxx.YYY."v_total__spx_enum_items_in_box" as a where a.minx = cminx and a.miny = cminy and a.maxx = cmaxx and a.maxy = cmaxy ) f_all; declare ptr integer; ptr := img_tostr (img); img_destroy (img); declare image any; image := img_fromptr(ptr); string_to_file('testx.gif', image, -2); return; }; mk_testx_gif(35., 50., 45., 60.); 
यह क्वेरी 17.4 सेकंड चलती है। इस प्रकार, आशावादी छिपे हुए जोड़ों को पहचानने और सौंदर्य के लिए बहुत नुकसान के बिना अनुरोध को निष्पादित करने में सक्षम था। सूचकांक के काम में एक छोटा सा लाभ अनुरोध की बढ़ी हुई जटिलता द्वारा खाया गया था।

और यहाँ परिणाम है:
छवि
इस नॉन्डस्क्रिप्ट चित्र में कई मिलियन ऑब्जेक्ट हैं।

निष्कर्ष


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

उदाहरण के लिए, तालिका 'हाईवे-लाइन' में विभिन्न प्रकार की दर्जनों परतों का एक जोड़ा होता है जो विशेषताओं में भिन्न होते हैं। आमतौर पर, ऐसी तालिकाएं सभी सड़क परतों के आधार के रूप में कार्य करती हैं जो एक ही भौतिक तालिका को संदर्भित करती हैं और फ़िल्टर में भिन्न होती हैं। बेशक, दो दर्जन की तुलना में एक तालिका के साथ काम करना अधिक सुविधाजनक है (यह बिंदु इस काम के लिए एक मकसद भी था)। फिर, हमारे पास इन सभी परतों के लिए एक सामान्य स्थानिक सूचकांक है।

लेकिन इसके नुकसान भी हैं। फिर भी, प्रत्येक परत को खींचने के लिए, आपको एक अलग SQL क्वेरी चलाने की आवश्यकता है। यानी हालांकि एक सूचकांक है, फिर भी इस पर कुछ खोज की जा रही हैं। आप जिस पर जीत सकते हैं, वह कैशिंग पेज है। एक अतिरिक्त सूचकांक की आवश्यकता है - रिकॉर्ड का प्रकार, उस पर खोज करना और नमूनों को पार करना भी आवश्यक है। इसके अलावा, चूंकि विभिन्न प्रकारों की वस्तुओं को मिलाया जाता है, इसलिए इस बात की संभावना कम होती है कि एक ही प्रकार की वस्तुएं एक साथ (एक ही पृष्ठ पर) दिखाई दें और इस तरह कुल रीडिंग में वृद्धि हो।

क्या होगा अगर, उदाहरण के लिए, हम 'हाइवे-लाइन' टेबल को उप-तालिकाओं के एक समूह में टाइप करके बिखेर देते हैं और उन सभी को एक स्थानिक सूचकांक में जोड़ देते हैं, जैसा कि हमने ऊपर किया था? इंडेक्स के साथ काम करने से इसमें बदलाव नहीं होगा, हमें इसमें केवल एक खोज की आवश्यकता होगी। डेटा के साथ काम करने के बाद से ही तेजी आएगी डेटा की स्थानीयता बढ़ेगी - एक ही प्रकार का डेटा, स्थानिक रूप से करीब, डिस्क पर अक्सर पास होगा। और अगर किसी भी प्रकार का डेटा खोज सीमा में नहीं है, तो यह बस संसाधित नहीं किया जाएगा। कोई फर्क नहीं पड़ता कि कितने हैं, यह उपयोगी डेटा पढ़ने को प्रभावित नहीं करेगा।

और एक आखिरी अवलोकन। इस तरह के सूचकांक अजीब वस्तुएं हैं। न तो रिलेशनल बीजगणित में और न ही रिलेशनल कैलकुलस में कोई करीबी होता है। यह एक कार्यान्वयन-विशिष्ट एक्सटेंशन है जो क्वेरी प्रोसेसर को अधिक कुशलता से निष्पादित करने की अनुमति देता है। हमारे मामले में, सूचक कुछ शब्दार्थों से भरे हुए हैं जो डेटा में नहीं हैं। हमारे मल्टी-टेबल इंडेक्स परतों के बीच संबंधों का वर्णन करते हैं, वास्तव में, एक विशेष इंडेक्स में वे परतें होती हैं जिन्हें हम एक साथ खींचना चाहते हैं।

दूसरी ओर, हम अपने सूचकांक को एक तालिका के रूप में नहीं देख सकते हैं (हालांकि वास्तव में यह एक तालिका है, यह इस तथ्य के कारण एक आवश्यक उपाय है कि हम एक विशिष्ट डीबीएमएस के भीतर रहने के लिए मजबूर हैं) क्योंकि इसके मान तालिका पहचानकर्ता हैं। यह एक मेटाबॉलिक है और क्वेरी प्लान इस पर मेटाडेटा पर निर्भर करता है।

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

पुनश्च:

एक उदाहरण के रूप में, लेख का शीर्षक उसी नाम की कहानी से मार्क ट्वेन के हाथों की अद्भुत पेरिस योजना का उपयोग करता है।

Source: https://habr.com/ru/post/In201474/


All Articles