टेबल स्कीमा
अपना नियम लागू करने के लिए बस pvanlagen.buildid
. घोषित करें UNIQUE
:
ALTER TABLE pvanlagen ADD CONSTRAINT pvanlagen_buildid_uni UNIQUE (buildid);
build.gid
पीके है, जैसा कि आपके अपडेट से पता चला है। संदर्भात्मक अखंडता को भी लागू करने के लिए एक विदेशी कुंजी
बाधा
करने के लिए बिल्डिंग.gid
।
आपने अब तक दोनों को लागू कर दिया है। लेकिन बड़े UPDATE
को चलाना अधिक कुशल होगा नीचे पहले आप इन बाधाओं को जोड़ते हैं।
आपकी तालिका परिभाषा में और भी बहुत कुछ सुधार किया जाना चाहिए। एक के लिए, builds.gid
साथ ही pvanlagen.buildid
पूर्णांक
type प्रकार का होना चाहिए (या संभवतः बिगिन्ट
अगर आप बहुत जलाते हैं पीके मूल्यों के)। संख्यात्मक
महंगा बकवास है।
आइए मुख्य समस्या पर ध्यान दें:
निकटतम भवन खोजने के लिए मूल प्रश्न
मामला इतना आसान नहीं है जितना लग रहा है। यह एक "निकटतम पड़ोसी" समस्या, अद्वितीय असाइनमेंट की अतिरिक्त जटिलता के साथ।
यह क्वेरी निकटतम एक . ढूंढती है प्रत्येक PV के लिए भवन (PV Anlage के लिए संक्षिप्त - pvanlagen
. में पंक्ति) ), जहां न तो असाइन किया गया है, फिर भी:
SELECT pv_gid, b_gid, dist
FROM (
SELECT gid AS pv_gid, ST_Transform(geom, 31467) AS geom31467
FROM pvanlagen
WHERE buildid IS NULL -- not assigned yet
) p
, LATERAL (
SELECT b.gid AS b_gid
, round(ST_Distance(p.geom31467
, ST_Transform(b.centroid, 31467))::numeric, 2) AS dist -- see below
FROM buildings b
LEFT JOIN pvanlagen p1 ON p1.buildid = b.gid -- also not assigned ...
WHERE p1.buildid IS NULL -- ... yet
-- AND p.gemname = b.gemname -- not needed for performance, see below
ORDER BY p.geom31467 <-> ST_Transform(b.centroid, 31467)
LIMIT 1
) b;
इस क्वेरी को तेज़ बनाने के लिए, आपको जरूरत इमारतों
. पर एक स्थानिक, कार्यात्मक जिस्ट इंडेक्स इसे काफी बनाने के लिए तेज़:
CREATE INDEX build_centroid_gix ON buildings USING gist (ST_Transform(centroid, 31467));
यकीन नहीं होता क्यों आप नहीं
अधिक स्पष्टीकरण के साथ संबंधित उत्तर:
- एक से अधिक सेल्फ़ जॉइन के साथ बड़ी टेबल पर स्थानिक क्वेरी धीमी गति से प्रदर्शन कर रही है
- मैं अपने निर्देशांकों के 5 मील के दायरे में सभी पंक्तियों को कैसे क्वेरी करूं?
आगे पढ़ना:
- http://workshops.boundlessgeo.com/postgis-intro/knn. एचटीएमएल
- http://www.postgresonline.com/journal/archives/306-KNN-GIST-with-a-Lateral-twist-Coming-soon-to-a-database-near- आप.html
अनुक्रमणिका के साथ, हमें मिलानों को उसी रत्न नाम
. तक सीमित करने की आवश्यकता नहीं है प्रदर्शन के लिए। ऐसा केवल तभी करें जब इसे लागू करने का एक वास्तविक नियम हो। यदि इसे हर समय देखा जाना है, तो कॉलम को FK बाधा में शामिल करें:
शेष समस्या
हम उपरोक्त क्वेरी का उपयोग UPDATE
. में कर सकते हैं बयान। प्रत्येक PV का उपयोग केवल एक बार किया जाता है, लेकिन एक से अधिक PV को अभी भी एक ही भवन मिल सकता है निकटतम होना। आप केवल एक की अनुमति देते हैं प्रति भवन पी.वी. तो आप इसका समाधान कैसे करेंगे?
दूसरे शब्दों में, आप यहाँ वस्तुओं को कैसे निर्दिष्ट करेंगे?
सरल समाधान
एक आसान उपाय होगा:
UPDATE pvanlagen p1
SET buildid = sub.b_gid
, dist = sub.dist -- actual distance
FROM (
SELECT DISTINCT ON (b_gid)
pv_gid, b_gid, dist
FROM (
SELECT gid AS pv_gid, ST_Transform(geom, 31467) AS geom31467
FROM pvanlagen
WHERE buildid IS NULL -- not assigned yet
) p
, LATERAL (
SELECT b.gid AS b_gid
, round(ST_Distance(p.geom31467
, ST_Transform(b.centroid, 31467))::numeric, 2) AS dist -- see below
FROM buildings b
LEFT JOIN pvanlagen p1 ON p1.buildid = b.gid -- also not assigned ...
WHERE p1.buildid IS NULL -- ... yet
-- AND p.gemname = b.gemname -- not needed for performance, see below
ORDER BY p.geom31467 <-> ST_Transform(b.centroid, 31467)
LIMIT 1
) b
ORDER BY b_gid, dist, pv_gid -- tie breaker
) sub
WHERE p1.gid = sub.pv_gid;
मैं DISTINCT ON (b_gid)
. का उपयोग करता हूं बिल्कुल एक . को कम करने के लिए प्रति भवन पंक्ति, कम से कम दूरी के साथ पीवी चुनना। विवरण:
किसी भी भवन के लिए जो एक से अधिक PV के निकटतम है, केवल निकटतम PV असाइन किया गया है। PK कॉलम gid
(उपनाम pv_gid
) टाईब्रेकर के रूप में कार्य करता है यदि दो समान रूप से निकट हों। ऐसी स्थिति में, कुछ PV अपडेट से हटा दिए जाते हैं और असाइन किए गए . रहते हैं . दोहराएं जब तक सभी पीवी असाइन नहीं हो जाते तब तक क्वेरी करें।
यह अभी भी एक सरल एल्गोरिथम है , यद्यपि। ऊपर दिए गए मेरे आरेख को देखते हुए, यह 4 से PV 4 और बिल्डिंग 5 से PV 5 को असाइन करता है, जबकि 4-5 और 5-4 शायद समग्र रूप से एक बेहतर समाधान होगा ...
इसके अलावा:dist
के लिए टाइप करें कॉलम
वर्तमान में आप numericका उपयोग करते हैं कोड>
इसके लिए। आपकी मूल क्वेरी ने एक स्थिर पूर्णांक
असाइन किया है , संख्यात्मक
में कोई मतलब नहीं है ।
मेरी नई क्वेरी में ST_Distance()
मीटर में वास्तविक दूरी को double के रूप में लौटाता है सटीक
. यदि हम केवल यह निर्दिष्ट करते हैं कि हमें संख्यात्मक
. में 15 या इतने ही भिन्नात्मक अंक प्राप्त होते हैं डेटा प्रकार, और संख्या वह नहीं है शुरू करने के लिए सटीक। मुझे गंभीरता से संदेह है कि आप संग्रहण को बर्बाद करना चाहते हैं।
इसके बजाय मैं मूल दोहरी सटीकता
को सहेजना चाहूंगा गणना से। या, अभी तक बेहतर , आवश्यकतानुसार गोल। यदि मीटर काफी सटीक हैं, तो बस एक पूर्णांक
. पर कास्ट करें और सहेजें (संख्या को स्वचालित रूप से गोल करना)। या सेमी को बचाने के लिए पहले 100 से गुणा करें:
(ST_Distance(...) * 100)::int