संशोधित तालिका परिभाषा
यदि आपको वास्तव में उन स्तंभों की आवश्यकता है NOT NULL
और आपको वास्तव में स्ट्रिंग की आवश्यकता है 'default'
engine_slug
. के लिए डिफ़ॉल्ट के रूप में , मैं कॉलम डिफ़ॉल्ट पेश करने की सलाह दूंगा:
COLUMN | TYPE | Modifiers
-----------------+-------------------------+---------------------
id | INTEGER | NOT NULL DEFAULT ...
engine_slug | CHARACTER VARYING(200) | NOT NULL DEFAULT 'default'
content_type_id | INTEGER | NOT NULL
object_id | text | NOT NULL
object_id_int | INTEGER |
title | CHARACTER VARYING(1000) | NOT NULL
description | text | NOT NULL DEFAULT ''
content | text | NOT NULL
url | CHARACTER VARYING(1000) | NOT NULL DEFAULT ''
meta_encoded | text | NOT NULL DEFAULT '{}'
search_tsv | tsvector | NOT NULL
...
DDL स्टेटमेंट होगा:
ALTER TABLE watson_searchentry ALTER COLUMN engine_slug DEFAULT 'default';
आदि।
फिर आपको उन मानों को हर बार मैन्युअल रूप से सम्मिलित करने की आवश्यकता नहीं है।
साथ ही:object_id text NOT NULL, object_id_int INTEGER
? यह अजीब है। मुझे लगता है कि आपके पास अपने कारण हैं ...
मैं आपकी अद्यतन आवश्यकता के साथ जाऊंगा:
बेशक, आपको जरूरी एक अद्वितीय जोड़ें आपकी आवश्यकताओं को लागू करने में बाधा:
ALTER TABLE watson_searchentry
ADD CONSTRAINT ws_uni UNIQUE (content_type_id, object_id_int)
संलग्न सूचकांक का उपयोग किया जाएगा। शुरुआत के लिए इस क्वेरी के द्वारा।
बीटीडब्ल्यू, मैं लगभग कभी भी varchar(n)
. का उपयोग नहीं करता हूं पोस्टग्रेज में। बस text
. ये रहा एक कारण।
डेटा-संशोधित सीटीई के साथ क्वेरी
इसे एक एकल SQL क्वेरी के रूप में डेटा-संशोधित सामान्य तालिका अभिव्यक्तियों के साथ फिर से लिखा जा सकता है, जिसे "लिखने योग्य" CTE भी कहा जाता है। पोस्टग्रेज 9.1 या बाद के संस्करण की आवश्यकता है।
इसके अतिरिक्त, यह क्वेरी केवल वही हटाती है जिसे हटाया जाना है, और जो अपडेट किया जा सकता है उसे अपडेट करता है।
WITH ctyp AS (
SELECT id AS content_type_id
FROM django_content_type
WHERE app_label = 'web'
AND model = 'member'
)
, sel AS (
SELECT ctyp.content_type_id
,m.id AS object_id_int
,m.id::text AS object_id -- explicit cast!
,m.name AS title
,concat_ws(' ', u.email,m.normalized_name,c.name) AS content
-- other columns have column default now.
FROM web_user u
JOIN web_member m ON m.user_id = u.id
JOIN web_country c ON c.id = m.country_id
CROSS JOIN ctyp
WHERE u.is_active
)
, del AS ( -- only if you want to del all other entries of same type
DELETE FROM watson_searchentry w
USING ctyp
WHERE w.content_type_id = ctyp.content_type_id
AND NOT EXISTS (
SELECT 1
FROM sel
WHERE sel.object_id_int = w.object_id_int
)
)
, up AS ( -- update existing rows
UPDATE watson_searchentry
SET object_id = s.object_id
,title = s.title
,content = s.content
FROM sel s
WHERE w.content_type_id = s.content_type_id
AND w.object_id_int = s.object_id_int
)
-- insert new rows
INSERT INTO watson_searchentry (
content_type_id, object_id_int, object_id, title, content)
SELECT sel.* -- safe to use, because col list is defined accordingly above
FROM sel
LEFT JOIN watson_searchentry w1 USING (content_type_id, object_id_int)
WHERE w1.content_type_id IS NULL;
-
django_content_type
. पर सबक्वेरी हमेशा एक ही मूल्य देता है? अन्यथा,CROSS JOIN
परेशानी पैदा कर सकता है। -
पहला सीटीई
sel
डालने के लिए पंक्तियों को इकट्ठा करता है। ध्यान दें कि मैं मेल खाने वाले कॉलम नामों को कैसे चुनता हूं चीजों को आसान बनाने के लिए। -
CTE
del
. में मैं उन पंक्तियों को हटाने से बचता हूँ जिन्हें अद्यतन किया जा सकता है। -
CTE में
up
इसके बजाय उन पंक्तियों को अपडेट किया जाता है। -
तदनुसार, मैं उन पंक्तियों को सम्मिलित करने से बचता हूँ जिन्हें पहले अंतिम
INSERT
. में हटाया नहीं गया था ।
बार-बार उपयोग के लिए आसानी से SQL या PL/pgSQL फ़ंक्शन में लपेटा जा सकता है।
भारी समवर्ती उपयोग के लिए सुरक्षित नहीं है। आपके पास मौजूद फ़ंक्शन से काफी बेहतर है, लेकिन समवर्ती लेखन के खिलाफ अभी भी 100% मजबूत नहीं है। लेकिन आपकी अद्यतन जानकारी के अनुसार यह कोई समस्या नहीं है।
अद्यतनों को DELETE और INSERT से बदलना बहुत अधिक महंगा हो सकता है या नहीं भी हो सकता है। MVCC के कारण आंतरिक रूप से प्रत्येक अद्यतन का परिणाम एक नई पंक्ति संस्करण में होता है। मॉडल ।
पहले गति करें
यदि आप वास्तव में पुरानी पंक्तियों को संरक्षित करने की परवाह नहीं करते हैं, तो आपका सरल दृष्टिकोण तेज़ हो सकता है:सब कुछ हटाएं और नई पंक्तियां डालें। साथ ही, एक plpgsql फ़ंक्शन में लपेटने से कुछ योजना ओवरहेड बचती है। आपका कार्य मूल रूप से, कुछ मामूली सरलीकरण और ऊपर जोड़े गए डिफ़ॉल्ट को देखकर:
CREATE OR REPLACE FUNCTION update_member_search_index()
RETURNS VOID AS
$func$
DECLARE
_ctype_id int := (
SELECT id
FROM django_content_type
WHERE app_label='web'
AND model = 'member'
); -- you can assign at declaration time. saves another statement
BEGIN
DELETE FROM watson_searchentry
WHERE content_type_id = _ctype_id;
INSERT INTO watson_searchentry
(content_type_id, object_id, object_id_int, title, content)
SELECT _ctype_id, m.id, m.id::int,m.name
,u.email || ' ' || m.normalized_name || ' ' || c.name
FROM web_member m
JOIN web_user u USING (user_id)
JOIN web_country c ON c.id = m.country_id
WHERE u.is_active;
END
$func$ LANGUAGE plpgsql;
मैं concat_ws()
:यह NULL
. से सुरक्षित है मूल्यों और कोड को सरल करता है, लेकिन साधारण संयोजन की तुलना में थोड़ा धीमा।
इसके अलावा:
इस फ़ंक्शन में तर्क को शामिल करना तेज़ होगा - यदि ट्रिगर की आवश्यकता केवल यही है। अन्यथा, यह शायद उपद्रव के लायक नहीं है।