अवांछनीय नेस्ट लूप बनाम हाश PostgreSQL 9.6 में शामिल हों


13

मुझे PostgreSQL 9.6 क्वेरी प्लानिंग से परेशानी है। मेरी क्वेरी इस तरह दिखती है:

SET role plain_user;

SELECT properties.*
FROM properties
JOIN entries_properties
  ON properties.id = entries_properties.property_id
JOIN structures
  ON structures.id = entries_properties.entry_id 
WHERE structures."STRUKTURBERICHT" != ''
  AND properties."COMPOSITION" LIKE 'Mo%'
  AND (
    properties."NAME" LIKE '%VASP-ase-preopt%'
    OR properties."CALCULATOR_ID" IN (7,22,25)
  )
AND properties."TYPE_ID" IN (6)

उपर्युक्त तालिकाओं के लिए मेरे पास रो-लेवल सुरक्षा सक्षम है।

  • के साथ set enable_nestloop = True, क्वेरी योजनाकार नेस्टेड लूप चलाता है, जो लगभग 37 सेकंड के कुल समय के साथ जुड़ता है: https://explain.depesz.com/s/59BR

  • साथ set enable_nestloop = False, हैश शामिल हों विधि का इस्तेमाल किया जाता है और क्वेरी समय 0.3 सेकंड के बारे में है: https://explain.depesz.com/s/PG8E

मैंने VACUUM ANALYZEप्रश्नों को चलाने से पहले किया था , लेकिन इससे मदद नहीं मिली।

मुझे पता है कि यह set enable_nestloop = Falseऔर योजनाकार के लिए किसी अन्य समान विकल्प के लिए एक अच्छा अभ्यास नहीं है । लेकिन मैं नेस्टेड लूप को अक्षम किए बिना हैश में शामिल होने के लिए प्लानर को कैसे मना सकता हूं?

क्वेरी को फिर से लिखना एक विकल्प है।

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

CREATE POLICY properties_select
ON properties
FOR SELECT
USING (
  (
    properties.ouid = get_current_user_id()
    AND properties.ur
  )
  OR (
    properties.ogid in (select get_current_groups_id())
    AND properties.gr
  )
  OR properties.ar
);

कोई भी विचार या सुझाव की बहुत सराहना की जाएगी।


बस थोड़ा उलझन में है: क्यों AND properties."TYPE_ID" IN (6);और क्या नहीं है = 6;?
Vérace

2
@ Vérace जबकि = अधिक व्यापक रूप से उपयोग किया जाता है, वे दोनों एक ही तरह से नियोजित हो जाते हैं। मेरी धारणा यह है कि वह एक से अधिक मूल्य के साथ खेल रहा है, या एक ORM एक आलसी आलसी है।
इवान कैरोल

जवाबों:


15

यहाँ क्या हो रहा है नेस्टेड लूप एक तरफ से रास्ता है। नेस्टेड लूप वास्तव में अच्छी तरह से काम करते हैं जब एक तरफ बहुत छोटा होता है, जैसे कि एक पंक्ति को वापस करना। आपकी क्वेरी में, योजनाकार यहां लड़खड़ाता है और अनुमान लगाता है कि हैश जॉइन सिर्फ एक पंक्ति में वापस आ जाएगा। इसके बजाय, हाश ज्वाइन (property_id = id) 1,338 पंक्तियों को लौटाता है। यह 1,338 छोरों को नेस्टड लूप के दूसरी तरफ चलाने के लिए मजबूर करता है जिसमें पहले से ही 3,444 पंक्तियां हैं। यह एक हेला-लॉट है जब आप केवल एक की उम्मीद कर रहे हैं (जो कि "लूप" से बहुत अधिक नहीं है)। Anywayy ..

इससे आगे की परीक्षा जैसे ही हम आगे बढ़ते हैं, यह दर्शाता है कि हाश ज्वाइन वास्तव में इससे उत्पन्न होने वाले अनुमानों से प्रभावित है,

Filter: (((properties."COMPOSITION")::text ~~ 'Mo%'::text) AND (((properties."NAME")::text ~~ '%VASP-ase-preopt%'::text) OR (properties."CALCULATOR_ID" = ANY ('{7,22,25}'::integer[]))))

PostgreSQL को उम्मीद है कि एक पंक्ति को वापस करना होगा। लेकिन यह नहीं है। और, यह वास्तव में आपकी समस्या है। तो यहाँ कुछ विकल्प हैं, जिसमें एक स्लेज हैमर को निकालना और अक्षम करना शामिल नहीं हैnested_loop

  • आप propertiesसंभावित रूप से seq स्कैन को पूरी तरह से छोड़ने या बेहतर तरीके से रिटर्न का अनुमान लगाने में मदद करने के लिए एक इंडेक्स या दो जोड़ सकते हैं ।

    CREATE INDEX ON properties USING ( "TYPE_ID", "CALCULATOR_ID" );
    -- the gist_trgm_ops may or may not be needed depending on selectivity of above.
    CREATE INDEX ON properties USING GIST (
      "COMPOSITION" gist_trgm_ops,
      "NAME"        gist_trgm_ops
    );
    ANALYZE properties;
    
  • वैकल्पिक रूप से, आप गुणों के सामान को CTE या सबसिलेक्ट में स्थानांतरित कर सकते हैं OFFSET 0जिसके साथ एक बाड़ बनाता है।

    WITH t AS (
      SELECT *
      FROM properties.
      WHERE "COMPOSITION" LIKE 'Mo%'
      AND (
        "NAME" LIKE '%VASP-ase-preopt%'
        OR "CALCULATOR_ID" IN (7,22,25)
      )
      AND "TYPE_ID" IN (6)
    )
    SELECT * FROM structures
    JOIN t ON (
      structures.id = entries_properties.entry_id
    )
    
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.