PostgreSQL Antipatterns: שינוי נתונים תוך עקיפת טריגר

במוקדם או במאוחר, רבים מתמודדים עם הצורך לתקן באופן מסיבי משהו ברשומות הטבלה. יש לי כבר תגיד לי איך לעשות את זה טוב יותר, ואיך - עדיף לא לעשות את זה. היום אדבר על ההיבט השני של העדכון ההמוני - לגבי טריגרים.

לדוגמה, על שולחן שבו אתה צריך לתקן משהו, הדק מרושע תלוי ON UPDATE, העברת כל השינויים לכמה אגרגטים. ואתה צריך לעדכן הכל (אתחול שדה חדש, למשל) כל כך בזהירות שהאגרגטים האלה לא יושפעו.

בואו פשוט נשבית את הטריגרים!

BEGIN;
  ALTER TABLE ... DISABLE TRIGGER ...;
  UPDATE ...; -- тут долго-долго
  ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;

למעשה, זה הכל - הכל תלוי.

בגלל ALTER TABLE כופה גישה בלעדית- מנעול שמתחתיו אף אחד לא רץ במקביל, אפילו פשוט SELECT, לא יוכל לקרוא דבר מהטבלה. כלומר, עד שהעסקה הזו תסתיים, כל מי שרוצה אפילו "רק לקרוא" יחכה. ואנחנו זוכרים את זה UPDATE יש לנו ארוך...

בואו נכבה אותו במהירות, ואז נפעיל אותו במהירות!

BEGIN;
  ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;

UPDATE ...;

BEGIN;
  ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;

כאן המצב כבר יותר טוב, זמן ההמתנה הרבה פחות. אבל רק שתי בעיות מקללות את כל היופי:

  • ALTER TABLE עצמה מחכה לכל שאר הפעולות על השולחן, כולל ארוכות SELECT
  • בזמן שההדק כבוי "לעוף ליד" כל שינוי בטבלה, אפילו לא שלנו. וזה לא ייכנס למצטברים, למרות שצריך. צרה!

ניהול משתני הפעלה

אז, בגרסה הקודמת, נתקלנו בנקודה בסיסית - אנחנו צריכים איכשהו ללמד את הטריגר להבחין בין השינויים "שלנו" בטבלה מ"לא שלנו". "שלנו" מדלגים כפי שהם, אבל ב"לא שלנו" הם מופעלים. בשביל זה אתה יכול להשתמש משתני הפעלה.

תפקיד_שכפול_סשן

קראנו מדריך ל:

מנגנון ההדק מושפע גם ממשתנה התצורה תפקיד_שכפול_סשן. מופעל ללא הוראות נוספות (ברירת מחדל), טריגרים יופעלו כאשר תפקיד השכפול הוא "מקור" (ברירת מחדל) או "מקומי". מפעילים מופעלים על ידי ציון ENABLE REPLICA, יעבוד רק אם מצב הפגישה הנוכחית - "רפליקה", וטריגרים מופעלים על ידי ציון ENABLE ALWAYS, יעבוד ללא קשר למצב השכפול הנוכחי.

אדגיש במיוחד שההגדרה לא חלה על הכל בבת אחת, כמו ALTER TABLE, אבל רק לחיבור המיוחד הנפרד שלנו. בסך הכל, כך שאף אפליקציה לא מפעילה עבודה:

SET session_replication_role = replica; -- выключили триггеры
UPDATE ...;
SET session_replication_role = DEFAULT; -- вернули в исходное состояние

מצב בתוך הדק

אבל האפשרות שלמעלה פועלת עבור כל הטריגרים בבת אחת (או שאתה צריך "לחליף" טריגרים מראש שאינך רוצה להשבית). ואם נצטרך "כבה" טריגר אחד ספציפי?

זה יעזור לנו משתנה הפעלה "משתמש".:

שמות פרמטרי ההרחבה נכתבים באופן הבא: שם ההרחבה ואחריו נקודה ולאחר מכן שם הפרמטר עצמו, בדומה לשמות אובייקטים מלאים ב-SQL. לדוגמה: plpgsql.variable_conflict.
מכיוון שניתן להגדיר אפשרויות מחוץ למערכת בתהליכים שאינם טוענים את מודול ההרחבה המתאים, PostgreSQL מקבל ערכים עבור כל שמות עם שני מרכיבים.

ראשית, אנו מסיימים את הטריגר, משהו כזה:

BEGIN
    -- процессу конвертации можно делать все
    IF current_setting('mycfg.my_table_convert_process') = 'TRUE' THEN
        IF TG_OP IN ('INSERT', 'UPDATE') THEN
            RETURN NEW;
        ELSE
            RETURN OLD;
        END IF;
    END IF;
...

אגב, אפשר לעשות זאת "למטרת רווח", בלי לחסום, דרך CREATE OR REPLACE עבור פונקציית ההדק. ואז בחיבור המיוחד אנו מפעילים את המשתנה "שלנו":


SET mycfg.my_table_convert_process = 'TRUE';
UPDATE ...;
SET mycfg.my_table_convert_process = ''; -- вернули в исходное состояние

האם אתה מכיר דרכים אחרות? שתפו בתגובות.

מקור: www.habr.com

הוספת תגובה