22 मई 2025·6 मिनट पढ़ने में

PostgreSQL जनरेटेड कॉलम्स से तेज़ एडमिन फ़िल्टर

जानें कैसे PostgreSQL जनरेटेड कॉलम एडमिन स्क्रीन के फ़िल्टर और सॉर्टिंग को तेज़ कर सकते हैं, साथ में व्यावहारिक उदाहरण और त्वरित जांच।

PostgreSQL जनरेटेड कॉलम्स से तेज़ एडमिन फ़िल्टर

क्यों एडमिन स्क्रीन जल्दी धीमी और उलझी हो जाती हैं

एडमिन स्क्रीन आमतौर पर साधारण शुरू होती हैं: एक तालिका, कुछ फ़िल्टर, शायद “नए पहले” से सॉर्ट। फिर असली काम शुरू होता है। सपोर्ट चाहता है कि ग्राहक का नाम, ईमेल, और फोन से खोज हो। सेल्स चाहता है “last activity” के अनुसार सॉर्ट। फाइनेंस चाहता है “overdue balance”। हर अनुरोध शर्तें, जॉइन और अतिरिक्त गणनाएं जोड़ देता है।

अधिकांश एडमिन लिस्ट्स उसी वजह से धीमी हो जाती हैं: हर क्लिक से क्वेरी बदल जाती है। फ़िल्टर और सॉर्टिंग डेटाबेस को बहुत सारी पंक्तियों को स्कैन करने के लिए मजबूर कर सकती है, खासकर जब क्वेरी को यह तय करने से पहले हर पंक्ति के लिए एक मान की गणना करनी पड़ती है कि क्या मिल रहा है।

एक आम मोड़ तब आता है जब WHERE और ORDER BY अभिव्यक्तियों से भर जाते हैं। साधारण कॉलम के बजाय आप lower(email), date_trunc('day', last_seen_at), या कई स्टेटस को एक "बकेट" में मैप करने वाला CASE स्टेटमेंट पर फ़िल्टर करते हैं। ये अभिव्यक्तियाँ सिर्फ धीमी ही नहीं होतीं, बल्कि SQL को पढ़ने में कठिन, इंडेक्स करने में मुश्किल और गलतियाँ होने में आसान बना देती हैं।

गंदा एडमिन SQL अक्सर कुछ दोहराए जाने वाले पैटर्न से आता है:

  • एक “सर्च” इनपुट जो अलग-अलग नियमों के साथ कई फ़ील्ड चेक करता है
  • एक व्युत्पन्न मान पर सॉर्टिंग (पूरा नाम, प्राथमिकता स्कोर, “last meaningful event”)
  • बिज़नेस नियमों की कई स्क्रीन पर कॉपी की गई नकल
  • छोटी “हेल्पर” चेज़ (trim, lower, coalesce) हर जगह बिखरी हुई
  • वही गणना कई जगह, सूची, फ़िल्टर और सॉर्टिंग में इस्तेमाल हो रही हो

टीम अक्सर इसे ऐप लेयर में छुपाने की कोशिश करती है: डायनामिक क्वेरी बिल्डर, कंडीशनल जॉइन, या कोड में पूर्व-गणना। यह काम कर सकता है, लेकिन यह लॉजिक को UI और डेटाबेस के बीच बाँट देता है, जिससे स्लो क्वेरीज को डिबग करना दर्दनाक हो जाता है।

लक्ष्य सीधा है: तेज़ क्वेरीज जो पढ़ने में आसान रहें। जब कोई कंप्यूटेड वैल्यू बार-बार कई एडमिन स्क्रीन पर दिखती है, तो PostgreSQL generated columns उस नियम को एक जगह रखकर डेटाबेस को उसे ऑप्टिमाइज़ करने देते हैं।

जनरेटेड कॉलम आसान भाषा में

एक generated column एक सामान्य तालिका कॉलम है जिसका मान दूसरे कॉलम से कैलकुलेट होता है। आप मान खुद नहीं लिखते। PostgreSQL उस अभिव्यक्ति के अनुसार मान भर देता है जिसे आप परिभाषित करते हैं।

PostgreSQL में generated columns स्टोर्ड होते हैं। PostgreSQL एक पंक्ति इन्सर्ट या अपडेट होने पर मान की गणना करता है, फिर उसे डिस्क पर अन्य कॉलमों की तरह सेव कर देता है। यह आम तौर पर एडमिन स्क्रीन के लिए वही चाहिए: तेज़ पढ़ाई और कंप्यूटेड वैल्यू को इंडेक्स करने की क्षमता।

यह हर क्वेरी के अंदर वही गणना करने से अलग है। यदि आप बार-बार WHERE lower(email) = lower($1) लिखते रहते हैं या last_name || ', ' || first_name पर सॉर्ट करते हैं, तो आप उसी लागत को बार-बार भोगते हैं और आपका SQL शोर से भर जाता है। एक generated column उस दोहराई जाने वाली गणना को टेबल परिभाषा में ले आता है। आपकी क्वेरीज सरल हो जाती हैं और परिणाम हर जगह सुसंगत रहता है।

जब स्रोत डेटा बदलता है, PostgreSQL उस पंक्ति के लिए generated मान को ऑटोमेटिक अपडेट कर देता है। आपकी एप्लिकेशन को इसे सिंक में रखने की याद रखने की ज़रूरत नहीं।

एक उपयोगी मानसिक मॉडल:

  • एक बार फार्मूला परिभाषित करें।
  • PostgreSQL इसे लिखते समय (writes) गणना करता है।
  • क्वेरीज इसे एक सामान्य कॉलम की तरह पढ़ती हैं।
  • क्योंकि यह स्टोर्ड है, आप इसे इंडेक्स भी कर सकते हैं।

अगर आप बाद में फार्मूला बदलते हैं, तो आपको स्कीमा बदलने की ज़रूरत होगी। इसे किसी भी माइग्रेशन की तरह प्लान करें, क्योंकि मौजूदा पंक्तियाँ नए अभिव्यक्ति के अनुरूप अपडेट होंगी।

फ़िल्टर और सॉर्टिंग में कंप्यूटेड फील्ड्स के अच्छे उपयोग

Generated columns तब चमकते हैं जब मान हमेशा अन्य कॉलमों से व्युत्पन्न होता है और आप अक्सर उस पर फ़िल्टर या सॉर्ट करते हैं। वे एक-बार के रिपोर्ट्स के लिए कम मददगार होते हैं।

उपयोगी सर्च-फ्रेंडली फ़ील्ड्स

एडमिन सर्च शायद कभी “शुद्ध” सर्च नहीं होती। लोग उम्मीद करते हैं कि बॉक्स गँदे टेक्स्ट, मिश्रित केस और अतिरिक्त स्पेस को संभाले। यदि आप एक generated “search key” संग्रहीत करते हैं जो पहले से सामान्यीकृत है, तो आपका WHERE क्लॉज़ पढ़ने में साफ और हर स्क्रीन पर समान रहता है।

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

उदाहरण: हर क्वेरी में lower(trim(first_name || ' ' || last_name)) दोहराने के बजाय full_name_key एक बार जनरेट करें और उसी पर फ़िल्टर करें।

मानवों जैसा सॉर्टिंग कीज

सॉर्टिंग वो जगह है जहाँ कंप्यूटेड फील्ड्स जल्दी लाभ देते हैं, क्योंकि सॉर्टिंग PostgreSQL को कई पंक्तियों के लिए अभिव्यक्तियों का मूल्यांकन करने के लिए मजबूर कर सकती है।

सामान्य सॉर्टिंग कीज में नंबरिक रैंक (प्लान टीयर को 1, 2, 3 में मैप करना), एक एकल “latest activity” टाइमस्टैम्प (जैसे दो टाइमस्टैम्प्स का max), या टेक्स्ट के रूप में सही सॉर्ट करने वाला पैडेड कोड शामिल हैं।

जब सॉर्ट की एक सामान्य इंडेक्स की गई कॉलम हो, तो ORDER BY बहुत सस्ता हो जाता है।

तेज़ फ़िल्टर के लिए व्युत्पन्न फ्लैग्स

एडमिन यूज़र्स चेकबॉक्स पसंद करते हैं जैसे “Overdue” या “High value।” जब लॉजिक स्थिर हो और केवल पंक्ति डेटा पर निर्भर हो, तब ये generated कॉलम के रूप में अच्छी तरह काम करते हैं।

उदाहरण के लिए, यदि एक ग्राहक सूची को “Has unread messages” और “Is overdue” चाहिए, तो एक generated has_unread boolean (from unread_count > 0) और is_overdue (from due_date < now() and paid_at is null) UI फ़िल्टर्स को सरल शर्तों में बदल देते हैं।

जनरेटेड कॉलम, इंडेक्स और अन्य विकल्पों के बीच चुनाव

एडमिन स्क्रीन को तीन चीज़ें चाहिए: तेज़ फ़िल्टरिंग, तेज़ सॉर्टिंग, और ऐसा SQL जो महीनों बाद भी पढ़ा जा सके। असली निर्णय यह है कि गणना कहाँ रहनी चाहिए: टेबल में, इंडेक्स में, व्यू में, या ऐप कोड में।

Generated columns अच्छा फिट होते हैं जब आप चाहते हैं कि मान एक वास्तविक कॉलम की तरह व्यवहार करे: संदर्भित करना आसान हो, SELECT में दिखाई दे, और नए फ़िल्टर जोड़ते समय भूलना मुश्किल हो। वे सामान्य इंडेक्स के साथ स्वाभाविक रूप से जोड़ते हैं।

Expression indexes इसे जोड़ने में तेज़ हो सकते हैं क्योंकि आपको टेबल परिभाषा नहीं बदलनी पड़ती। यदि आप मुख्य रूप से स्पीड चाहते हैं और गंदा SQL पसंद कर सकते हैं, तो एक expression index अक्सर पर्याप्त होता है। नुकसान यह है कि पठनीयता कम होती है और आप प्लानर के सही अभिव्यक्ति मिलान पर निर्भर रहते हैं।

Views तब मदद करते हैं जब आप एक साझा "shape" चाहते हैं, खासकर अगर आपकी एडमिन सूची कई तालिकाओं को जोड़ती है। पर जटिल व्यू महंगी काम छिपा सकते हैं और डिबग के लिए दूसरी जगह जोड़ देते हैं।

Triggers एक सामान्य कॉलम को सिंक में रख सकते हैं, लेकिन वे अतिरिक्त मूविंग पार्ट्स जोड़ते हैं। वे बड़े बैच अपडेट्स को धीमा कर सकते हैं और ट्रबलशूटिंग के दौरान आसानी से ओवरलुक हो सकते हैं।

कभी-कभी सबसे अच्छा विकल्प ऐप द्वारा भरा गया सामान्य कॉलम ही होता है। अगर उपयोगकर्ता उसे एडिट कर सकते हैं, या फार्मूला अक्सर बदलता है (बिज़नेस निर्णयों के कारण), तो इसे स्पष्ट रखना बेहतर होता है।

एक त्वरित तरीका चुनने का:

  • पठनीय क्वेरीज और केवल पंक्ति डेटा पर आधारित स्थिर फार्मूला चाहिए? Generated column इस्तेमाल करें।
  • किसी विशेष फ़िल्टर के लिए स्पीड चाहिए और गंदा SQL चलेगा? Expression index लें।
  • कई जगहों पर फिर से उपयोग होने वाला जुड़ा हुआ, रिपोर्ट जैसा आकार चाहिए? व्यू पर विचार करें।
  • क्रॉस-टेबल लॉजिक या साइड-इफेक्ट चाहिए? पहले ऐप लॉजिक, ट्रिगर्स अंतिम विकल्प।

कदम-दर-कदम: एक generated column जोड़ें और क्वेरी में उपयोग करें

Ship better admin search
Add a normalized search key and hook it to simple filters your team understands.
Build Admin

एक धीमी एडमिन लिस्ट क्वेरी से शुरू करें जिसे आप UI में महसूस कर सकें। उन फ़िल्टर्स और सॉर्ट्स को लिखें जिन्हें स्क्रीन सबसे ज्यादा इस्तेमाल करती है। पहले उस एक क्वेरी को सुधारें।

एक कंप्यूटेड फ़ील्ड चुनें जो दोहराए जाने वाले काम को हटा दे, और इसे snake_case में स्पष्ट नाम दें ताकि दूसरों को बिना अभिव्यक्ति पढ़े ही अंदाज़ा हो जाए कि इसमें क्या है।

1) generated column (STORED) जोड़ें

ALTER TABLE customers
ADD COLUMN full_name_key text
GENERATED ALWAYS AS (
  lower(concat_ws(' ', last_name, first_name))
) STORED;

इंडेक्स जोड़ने से पहले असली पंक्तियों पर वैरिफाइ करें:

SELECT id, first_name, last_name, full_name_key
FROM customers
ORDER BY id DESC
LIMIT 5;

अगर आउटपुट गलत है, तो अभी अभिव्यक्ति ठीक करें। STORED का मतलब है PostgreSQL इसे हर insert और update पर अपडेट रखेगा।

2) उस इंडेक्स को जोड़ें जो आपके एडमिन स्क्रीन से मैच करता है

अगर आपका एडमिन स्क्रीन status से फ़िल्टर करता है और नाम से सॉर्ट करता है, तो उस पैटर्न को इंडेक्स करें:

CREATE INDEX customers_status_full_name_key_idx
ON customers (status, full_name_key);

3) एडमिन क्वेरी को नए कॉलम का उपयोग करने के लिए अपडेट करें

पहले आपके पास गंदा ORDER BY हो सकता था। अब यह स्पष्ट है:

SELECT id, status, first_name, last_name
FROM customers
WHERE status = 'active'
ORDER BY full_name_key ASC
LIMIT 50 OFFSET 0;

Generated columns का उपयोग उन हिस्सों के लिए करें जिन पर लोग हर दिन फ़िल्टर और सॉर्ट करते हैं, न कि दुर्लभ स्क्रीन के लिए।

इंडेक्सिंग पैटर्न जो वास्तविक एडमिन स्क्रीन से मेल खाते हैं

Reuse business rules
Define status buckets and flags once so every admin view matches.
Start Project

एडमिन स्क्रीन कुछ व्यवहार दोहराती हैं: कुछ फ़ील्ड्स से फ़िल्टर, एक कॉलम से सॉर्ट, और पेजिनेशन। सबसे अच्छा सेटअप "सब कुछ इंडेक्स करें" नहीं होता। यह होता है: सबसे सामान्य क्वेरीज के सही आकार को इंडेक्स करें।

एक व्यावहारिक नियम: सबसे सामान्य फ़िल्टर कॉलम पहले रखें, और सबसे सामान्य सॉर्ट कॉलम अंत में रखें। अगर आप multi-tenant हैं, तो workspace_id अक्सर पहले आता है: (workspace_id, status, created_at)

टेक्स्ट सर्च अलग समस्या है। कई सर्च बॉक्स ILIKE '%term%' बन जाते हैं, जिसे बेसिक btree इंडेक्स से तेज़ करना मुश्किल है। एक सहायक पैटर्न यह है कि कच्चे टेक्स्ट के बजाय एक सामान्यीकृत हेल्पर कॉलम पर सर्च करें (lowercase, trimmed, शायद concat)। अगर आपका UI prefix सर्च (term%) कर सकता है, तो उस सामान्यीकृत कॉलम पर btree इंडेक्स मदद कर सकता है। अगर contains सर्च (%term%) ज़रूरी है, तो UI व्यवहार कड़ा करें या सर्च को छोटे सबसेट तक सीमित करें।

इंडेक्स जोड़ने से पहले selectivity भी देखें। अगर 95% पंक्तियाँ एक ही मान साझा करती हैं (जैसे status = 'active'), तो सिर्फ उसी कॉलम को इंडेक्स करना ज्यादा मदद नहीं करेगा। इसे एक अधिक चयनात्मक कॉलम के साथ पेयर करें, या minority केस के लिए partial index का उपयोग करें।

वास्तविकतैनिक उदाहरण: एक ग्राहक एडमिन सूची जो तेज रहती है

एक सामान्य ग्राहक एडमिन पेज की कल्पना करें: एक सर्च बॉक्स, कुछ फ़िल्टर्स (inactive, balance range), और एक sortable "Last seen" कॉलम। समय के साथ यह जटिल SQL में बदल जाता है: LOWER(), TRIM(), COALESCE(), तारीख की गणनाएं, और CASE ब्लॉक्स जो स्क्रीन-टू-स्क्रीन दोहराए जाते हैं।

इन चीज़ों को generated columns में धकेलकर आप इसे तेज और पठनीय रख सकते हैं।

टेबल और generated कॉलम्स

मान लीजिए customers टेबल में name, email, last_seen, और balance हैं। तीन कंप्यूटेड फील्ड जोड़ें:

  • search_key: सादा सर्च के लिए सामान्यीकृत टेक्स्ट
  • is_inactive: एक boolean जिसे बार-बार तारीख लॉजिक दोहराने के बिना फ़िल्टर कर सकें
  • balance_bucket: तेजी से सेगमेंटेशन के लिए एक लेबल
ALTER TABLE customers
  ADD COLUMN search_key text
    GENERATED ALWAYS AS (
      lower(trim(coalesce(name, ''))) || ' ' || lower(trim(coalesce(email, '')))
    ) STORED,
  ADD COLUMN is_inactive boolean
    GENERATED ALWAYS AS (
      last_seen IS NULL OR last_seen < (now() - interval '90 days')
    ) STORED,
  ADD COLUMN balance_bucket text
    GENERATED ALWAYS AS (
      CASE
        WHEN balance < 0 THEN 'negative'
        WHEN balance < 100 THEN '0-99'
        WHEN balance < 500 THEN '100-499'
        ELSE '500+'
      END
    ) STORED;

अब एडमिन क्वेरी UI की तरह पढ़ती है।

पठनीय फ़िल्टर + सॉर्टिंग

“Inactive customers, newest activity first” बन जाता है:

SELECT id, name, email, last_seen, balance
FROM customers
WHERE is_inactive = true
ORDER BY last_seen DESC NULLS LAST
LIMIT 50;

और एक बेसिक सर्च बन जाता है:

SELECT id, name, email, last_seen, balance
FROM customers
WHERE search_key LIKE '%' || lower(trim($1)) || '%'
ORDER BY last_seen DESC NULLS LAST
LIMIT 50;

असल जीत सुसंगतता है। वही फ़ील्ड कई स्क्रीन शक्तिवान बनाती हैं बिना लॉजिक दोहराए:

  • ग्राहक सूची का सर्च बॉक्स search_key का उपयोग करता है
  • “Inactive customers” टैब is_inactive का उपयोग करता है
  • बैलेंस फ़िल्टर चिप्स balance_bucket का उपयोग करते हैं

सामान्य गलतियाँ और जाल

Add common modules fast
Add authentication and Stripe payments modules when your admin tool needs them.
Add Modules

Generated columns सरल जीत की तरह दिख सकते हैं: गणित टेबल में रखें और क्वेरीज साफ रखें। वे तभी मदद करते हैं जब वे स्क्रीन के फ़िल्टर और सॉर्ट से मेल खाते हों और आपने सही इंडेक्स जोड़ा हो।

सबसे सामान्य गलतियाँ:

  • यह मान लेना कि इंडेक्सिंग के बिना यह तेज़ कर देगा। एक कंप्यूटेड वैल्यू को स्केल पर फ़िल्टर या सॉर्ट करने के लिए फिर भी इंडेक्स चाहिए।
  • बहुत ज़्यादा लॉजिक एक फ़ील्ड में पैक कर देना। अगर एक generated column एक छोटा प्रोग्राम बन जाए, तो लोग उस पर भरोसा करना बंद कर देंगे। इसे संक्षेप रखें और स्पष्ट नाम दें।
  • non-immutable फ़ंक्शन्स का उपयोग करना। PostgreSQL स्टोर्ड generated कॉलम के लिए अभिव्यक्ति को immutable होने की आवश्यकता रखता है। now() और random() जैसी चीज़ें उम्मीदें तोड़ देती हैं और अक्सर अनुमति नहीं होतीं।
  • write कॉस्ट को नज़रअंदाज़ करना। इन्सर्ट्स और अपडेट्स को कंप्यूटेड वैल्यू बनाए रखना पड़ता है। यदि आप बहुत सारे generated फील्ड या जटिल अभिव्यक्तियाँ जोड़ते हैं तो imports और integrations धीमे हो सकते हैं।
  • लगभग-डुप्लिकेट बनाना। एक या दो मानक पैटर्न (जैसे एक सामान्यीकृत key) को स्टैंडर्डाइज़ करें बजाय पांच समान कॉलम जोड़ने के।

यदि आपकी एडमिन सूची contains सर्च (जैसे ILIKE '%ann%') करती है, तो एक generated column अकेले इसे नहीं बचा पाएगा। आपको अलग सर्च अप्रोच की ज़रूरत हो सकती है। लेकिन रोज़मर्रा के “filter and sort” वर्कहॉर्स क्वेरीज के लिए, generated columns और सही इंडेक्स आमतौर पर प्रदर्शन को अधिक भविष्यवाणी योग्य बनाते हैं।

शिप करने से पहले त्वरित चेकलिस्ट

Automate admin actions
Use the Business Process Editor to automate actions from admin screens.
Build Workflow

किसी एडमिन सूची में परिवर्तन डालने से पहले सुनिश्चित करें कि कंप्यूटेड वैल्यू, क्वेरी और इंडेक्स मेल खाते हैं।

  • फार्मूला स्थिर है और एक वाक्य में आसानी से बतायी जा सकती है।
  • आपकी क्वेरी वास्तव में generated कॉलम को WHERE और/या ORDER BY में उपयोग कर रही है।
  • इंडेक्स असली उपयोग से मेल खाता है, न कि एक-बार के टेस्ट से।
  • आपने पुराने लॉजिक की तुलना किनारे मामलों (NULLs, खाली स्ट्रिंग्स, अजीब स्पेसिंग, मिक्स्ड केस) पर की है।
  • यदि तालिका व्यस्त है (imports, background updates, integrations), तो आपने write प्रदर्शन का परीक्षण किया है।

अगले कदम: इसे अपनी एडमिन स्क्रीन पर लागू करें

छोटे, हाई-इम्पैक्ट शुरुआत बिंदु चुनें: 2-3 एडमिन स्क्रीन जो लोग दिन भर खोलते हैं (orders, customers, tickets)। लिख लें क्या धीमा लगता है (एक तारीख रेंज फ़िल्टर, “last activity” से सॉर्ट, संयुक्त नाम से सर्च, स्टेटस लेबल से फ़िल्टर)। फिर कुछ साझा कंप्यूटेड फील्ड स्टैंडर्डाइज़ करें जिनका आप कई स्क्रीन में पुन: उपयोग कर सकें।

एक रोलआउट प्लान जो नापना आसान और वापस लिया जा सके:

  • स्पष्ट नामों के साथ generated column(s) जोड़ें।
  • यदि आप मौजूदा लॉजिक बदल रहे हैं तो थोड़ी देर के लिए पुराने और नए को साइड-बाइ-साइड चलाएं।
  • मुख्य फ़िल्टर या सॉर्ट से मेल खाने वाला इंडेक्स जोड़ें।
  • स्क्रीन की क्वेरी को नए कॉलम का उपयोग करने के लिए स्विच करें।
  • पहले और बाद में मापें (क्वेरी समय और स्कैन की गई पंक्तियाँ), फिर पुराने वर्कअराउंड को हटा दें।

यदि आप AppMaster (appmaster.io) में आंतरिक एडमिन टूल बना रहे हैं, तो ये कंप्यूटेड फील्ड एक साझा डेटा मॉडल में अच्छी तरह फिट होते हैं: डेटाबेस नियम संभालता है, और आपकी UI फ़िल्टर एक सरल फ़ील्ड नाम की ओर इशारा कर सकती हैं बजाय कि स्क्रीन-स्क्रीन पर अभिव्यक्तियाँ दोहराने के।

सामान्य प्रश्न

When should I use a PostgreSQL generated column for an admin screen?

Generated columns help when you keep repeating the same expression in WHERE or ORDER BY, like normalizing names, mapping statuses, or building a sorting key. They’re especially useful for admin lists that are opened all day and need predictable filtering and sorting.

What’s the difference between a stored generated column and an expression index?

A stored generated column is computed on insert or update and saved like a normal column, so reads can be fast and indexable. An expression index stores the result in the index without adding a new table column, but your queries still need to use the exact expression for the planner to match it.

Will a generated column automatically make my query faster?

No, not by itself. A generated column mainly makes the query simpler and makes indexing a computed value straightforward, but you still need an index that matches your common filters and sorts if you want real speedups at scale.

What are the best generated columns to add for admin search and sorting?

Usually it’s a field you filter or sort on constantly: a normalized search key, a “full name” sort key, a derived boolean like is_overdue, or a ranking number that matches how people expect results to sort. Pick one value that removes repeated work from many queries, not a one-off calculation.

How do I choose the right index for an admin list that filters and sorts?

Start with the most common filter columns, then put the main sort key last, like (workspace_id, status, full_name_key) if that matches the screen. This lets PostgreSQL filter quickly and then return rows already ordered without extra work.

Can generated columns fix slow contains search like ILIKE '%term%'?

Not very. A generated column can normalize text so behavior is consistent, but ILIKE '%term%' still tends to be slow with basic btree indexes on large tables. If performance matters, prefer prefix-style search where you can, reduce the searched dataset with other filters, or adjust the UI behavior for big tables.

Can I create a generated column that depends on now() for “inactive” flags?

Stored generated columns have to be based on immutable expressions, so functions like now() typically aren’t allowed and would also be conceptually wrong because the value would go stale. For time-based flags like “inactive for 90 days,” consider a normal column maintained by a job, or compute it at query time if it’s not heavily used.

What happens if I need to change the formula of a generated column later?

Yes, but plan it like a real migration. Changing the expression means updating the schema and recomputing values for existing rows, which can take time and add write load, so do it in a controlled deployment window if the table is large.

Do generated columns add overhead to inserts and updates?

Yes. The database has to compute and store the value on every insert and update, so heavy write workloads (imports, sync jobs) can slow down if you add too many generated fields or complex expressions. Keep expressions short, add only what you use, and measure write performance on busy tables.

What’s the safest way to roll out generated columns to speed up an existing admin screen?

Add a generated column, validate a few real rows, then add the index that matches the screen’s main filter and sort. Update the admin query to use the new column directly, and compare query time and rows scanned before and after to confirm the change helped.

शुरू करना आसान
कुछ बनाएं अद्भुत

फ्री प्लान के साथ ऐपमास्टर के साथ प्रयोग करें।
जब आप तैयार होंगे तब आप उचित सदस्यता चुन सकते हैं।

शुरू हो जाओ