मैं PostgreSQL में छंटनी के साथ निश्चित संख्या वाली पंक्तियों को कैसे हटाऊं?


107

मैं कुछ पुराने MySQL प्रश्नों को PostgreSQL में पोर्ट करने की कोशिश कर रहा हूं, लेकिन मुझे इससे परेशानी हो रही है:

DELETE FROM logtable ORDER BY timestamp LIMIT 10;

PostgreSQL अपने डिलीट सिंटैक्स में ऑर्डर या सीमा की अनुमति नहीं देता है, और तालिका में एक प्राथमिक कुंजी नहीं है, इसलिए मैं एक सबक्वेरी का उपयोग नहीं कर सकता। इसके अतिरिक्त, मैं उस व्यवहार को संरक्षित करना चाहता हूं जहां क्वेरी बिल्कुल दिए गए नंबर या रिकॉर्ड को हटा देती है - उदाहरण के लिए, यदि तालिका में 30 पंक्तियाँ हैं, लेकिन वे सभी समान टाइमस्टैम्प हैं, मैं अभी भी 10 को हटाना चाहता हूं, हालांकि यह कोई फर्क नहीं पड़ता जो १०।

इसलिए; मैं PostgreSQL में छंटनी के साथ पंक्तियों की एक निश्चित संख्या को कैसे हटाऊं?

संपादित करें: कोई प्राथमिक कुंजी का अर्थ है कि कोई log_idस्तंभ या समान नहीं है। आह, विरासत प्रणालियों की खुशियाँ!


1
प्राथमिक कुंजी क्यों नहीं जोड़ें? पीस ओ 'केक इन पोस्टग्रैक्कल alter table foo add column id serial primary key:।
वेन कॉनराड

यह मेरा प्रारंभिक दृष्टिकोण था, लेकिन अन्य आवश्यकताएं इसे रोकती हैं।
व्हाट्सएप

जवाबों:


159

आप ctidनिम्न का उपयोग करके देख सकते हैं :

DELETE FROM logtable
WHERE ctid IN (
    SELECT ctid
    FROM logtable
    ORDER BY timestamp
    LIMIT 10
)

ctidहै:

अपनी तालिका के भीतर पंक्ति संस्करण का भौतिक स्थान। ध्यान दें कि यद्यपि ctidपंक्ति संस्करण को बहुत जल्दी पता लगाने के लिए उपयोग किया जा सकता है, ctidयदि यह अद्यतन या इसके द्वारा स्थानांतरित किया जाता है, तो पंक्ति का स्वरूप बदल जाएगा VACUUM FULL। इसलिए ctidएक लंबी अवधि की पंक्ति पहचानकर्ता के रूप में बेकार है।

वहाँ भी है, oidलेकिन यह केवल तब होता है जब आप विशेष रूप से तालिका बनाते समय इसके लिए पूछते हैं।


यह काम करता है, लेकिन यह कितना विश्वसनीय है? वहाँ किसी भी 'gotchas' के लिए मैं बाहर देखने की जरूरत है? VACUUM FULLयदि ctidक्वेरी चल रही है, तो क्या यह संभव है कि ऑटोबाकुम के लिए समस्या हो सकती है यदि वे तालिका में मूल्यों को बदलते हैं ?
व्हाट्सएप

2
वृद्धिशील VACUUMs ctids नहीं बदलेगा, मुझे नहीं लगता। चूँकि प्रत्येक पृष्ठ के भीतर सिर्फ काम्पैक्ट होता है, और ctid सिर्फ एक पृष्ठ ऑफसेट न होकर लाइन नंबर है। VACUUM FULL या CLUSTER ऑपरेशन से ctid बदल जाएगा , लेकिन उन ऑपरेशनों में पहले टेबल पर एक्सेस एक्सक्लूसिव लॉक लगता है।
अरकनिद

@Whatsit: ctidप्रलेखन की मेरी धारणा यह है कि ctidइस DELETE को ठीक बनाने के लिए पर्याप्त स्थिर है, लेकिन इतना स्थिर नहीं है, उदाहरण के लिए, एक अन्य तालिका में यहूदी बस्ती-एफके के रूप में रखा गया है। संभवत: आप इसे अपडेट नहीं करते हैं, logtableइसलिए आपको उस बदलते ctidएस के बारे में चिंता करने की ज़रूरत नहीं है और VACUUM FULLतालिका को लॉक करते हैं ( postgresql.org/docs/current/static/routine-vacuuming.html ) ताकि आपको चिंता करने की ज़रूरत न हो: दूसरा तरीका जो ctidबदल सकता है। @ araqnid का PostgreSQL-Fu बहुत मजबूत है और डॉक्स उसे बूट करने के लिए सहमत हैं।
म्यू बहुत छोटा है

स्पष्टीकरण के लिए आप दोनों को धन्यवाद। मैंने डॉक्स में देखा, लेकिन मुझे यकीन नहीं था कि मैं उन्हें सही ढंग से व्याख्या कर रहा हूं। मैं इससे पहले कभी ctids का सामना नहीं किया था।
व्हाट्सएप

यह वास्तव में एक बहुत बुरा समाधान है क्योंकि Postgres जुड़ने में TID स्कैन का उपयोग करने में सक्षम नहीं है (IN का एक विशेष मामला है)। यदि आप योजना को देखते हैं, तो यह काफी भयानक होना चाहिए। तो "बहुत जल्दी" केवल तभी लागू होता है जब आप स्पष्ट रूप से सीटीआईडी ​​निर्दिष्ट करते हैं। कहा जाता है संस्करण 10 के रूप में
महानवचन

53

डाक डॉक्स IN और सबक्वेरी के बजाय सरणी का उपयोग करने की सलाह देते हैं। यह बहुत तेजी से काम करना चाहिए

DELETE FROM logtable 
WHERE id = any (array(SELECT id FROM logtable ORDER BY timestamp LIMIT 10));

यह और कुछ अन्य तरकीबें यहां देखी जा सकती हैं


@Konrad Garus यहाँ आप लिंक पर जाएँ , 'फ़ास्ट फर्स्ट एन रो
रिमूव्स

1
@BlakeRegalia नहीं, क्योंकि निर्दिष्ट तालिका में कोई प्राथमिक कुंजी नहीं है। यह पहले 10. में पाए गए "ID" वाली सभी पंक्तियों को हटा देगा। यदि सभी पंक्तियों में समान ID है तो सभी पंक्तियाँ हटा दी जाएंगी।
फिलिप व्हाइटहाउस

6
यदि क्वेरी ऑप्टिमाइज़र में बग जैसा लगता है any (array( ... ));तो उससे अधिक तेज़ है in ( ... )- यह उस परिवर्तन को स्पॉट करने में सक्षम होना चाहिए और डेटा के साथ ही कार्य करना चाहिए।
rjmunro

1
मैंने इस विधि को INएक UPDATE(जो अंतर हो सकता है) का उपयोग करने की तुलना में काफी धीमा पाया ।
jmervine

1
12 जीबी टेबल पर माप: पहली क्वेरी 450..1000 एमएस, दूसरा एक 5..7 सेकंड: तेजी से एक: cs_log से हटाएं जहां id = किसी भी (सरणी (cs_log से आईडी का चयन करें जहां date_created <अब () - अंतराल '1 दिन) '* 30 और पार्टीशन_की तरह'% I 'ऑर्डर से आईडी लिमिट 500)) धीमा एक: सीएस_लॉगिंग से डिलीट करें जहां आईडी इन (सीएस से आईडी को सिलेक्ट करें जहां डेट_क्रिएट किया गया <अब () - इंटरवल' 1 दिन '30) और पार्टीशन' जैसे '% मैं 'id लिमिट 500' द्वारा ऑर्डर करता हूं)। Ctid का उपयोग करना बहुत धीमा (मिनट) था।
गुइडो लेन्डर्स


2

यह मानकर कि आप ऐसा करने के लिए कोई 10 रिकॉर्ड (आदेश के बिना) हटाना चाहते हैं:

DELETE FROM logtable as t1 WHERE t1.ctid < (select t2.ctid from logtable as t2  where (Select count(*) from logtable t3  where t3.ctid < t2.ctid ) = 10 LIMIT 1);

मेरे उपयोग के मामले में, 10M रिकॉर्ड हटाते हुए, यह तेज़ हो गया।


1

आप एक प्रक्रिया लिख ​​सकते हैं जो अलग-अलग लाइनों के लिए डिलीट हो जाती है, यह प्रक्रिया आपके द्वारा डिलीट की जाने वाली वस्तुओं की संख्या को निर्दिष्ट करने के लिए एक पैरामीटर ले सकती है। लेकिन वह MySQL की तुलना में थोड़ा ओवरकिल है।


0

यदि आपके पास एक प्राथमिक कुंजी नहीं है, तो आप उस सरणी का उपयोग कर सकते हैं जहां एक समग्र कुंजी के साथ वाक्य रचना में।

delete from table1 where (schema,id,lac,cid) in (select schema,id,lac,cid from table1 where lac = 0 limit 1000);

इसने मेरे लिए काम किया।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.