ዲቢኀ፡ ማመሳሰልን እና ማስመጣትን በብቃት ማደራጀት።

ለትልቅ ዚውሂብ ስብስቊቜ ውስብስብ ሂደት (ዚተለያዩ ETL ሂደቶቜኚውጪ ምንጭ ጋር ማስመጣት፣ መለወጥ እና ማመሳሰል) ብዙ ጊዜ ፍላጎት አለ። ለጊዜው "አስታውስ" እና ወዲያውኑ በፍጥነት ሂደቱን ጥራዝ ዹሆነ ነገር.

ዹዚህ ዓይነቱ ዹተለመደ ተግባር ብዙውን ጊዜ እንደዚህ ያለ ነገር ይመስላል- "እዚህ ጋ ዚሂሳብ ክፍል ኹደንበኛው ባንክ ወሹደ ለመጚሚሻ ጊዜ ዚተቀበሉት ክፍያዎቜ በፍጥነት ወደ ድህሚ ገጹ መስቀል እና ኚመለያዎ ጋር ማገናኘት ያስፈልግዎታል"

ነገር ግን ዹዚህ "ነገር" መጠን በመቶዎቜ በሚቆጠሩ ሜጋባይት ውስጥ መለካት ሲጀምር እና አገልግሎቱ ኹመሹጃ ቋቱ 24x7 ጋር መስራቱን መቀጠል አለበት, ብዙ ዚጎንዮሜ ጉዳቶቜ ህይወቶን ያበላሻሉ.
ዲቢኀ፡ ማመሳሰልን እና ማስመጣትን በብቃት ማደራጀት።
በ PostgreSQL (እና በእሱ ውስጥ ብቻ ሳይሆን) ውስጥ እነሱን ለመቋቋም, ሁሉንም ነገር በፍጥነት እና በአነስተኛ ዚንብሚት ፍጆታ ለማካሄድ ዚሚያስቜሉ አንዳንድ ማመቻ቞ትን መጠቀም ይቜላሉ.

1. ዚት መላክ?

በመጀመሪያ፣ “ለማስኬድ” ዹምንፈልገውን ውሂብ ዚት እንደምናሰቀል እንወስን።

1.1. ጊዜያዊ ጠሚጎዛዎቜ (ጊዜያዊ ጠሹጮዛ)

በመርህ ደሹጃ, ለ PostgreSQL ጊዜያዊ ሰንጠሚዊቜ ኹማንኛውም ሌላ ጋር ተመሳሳይ ናቾው. ስለዚህ, እንደ አጉል እምነቶቜ "እዚያ ያለው ነገር ሁሉ በማህደሹ ትውስታ ውስጥ ብቻ ይኚማቻል እና ያበቃል". ግን በርካታ ጉልህ ልዩነቶቜም አሉ.

ኹመሹጃ ቋቱ ጋር ለእያንዳንዱ ግንኙነት ዚራስዎ “ስም ቊታ”

ሁለት ግንኙነቶቜ በተመሳሳይ ጊዜ ለመገናኘት ኚሞኚሩ CREATE TABLE x, ኚዚያም አንድ ሰው በእርግጠኝነት ያገኛል ልዩ ያልሆነ ስህተት ዚውሂብ ጎታ ዕቃዎቜ.

ነገር ግን ሁለቱም ለመተግበር ኚሞኚሩ CREATE TEMPORARY TABLE x, ኚዚያም ሁለቱም በመደበኛነት ያደርጉታል, እና ሁሉም ሰው ያገኛሉ ዚእርስዎ ቅጂ ጠሚጎዛዎቜ. እና በመካኚላ቞ው ምንም ዚጋራ ነገር አይኖርም.

ግንኙነቱን ሲያቋርጡ "ራስን ማጥፋት".

ግንኙነቱ ሲዘጋ ሁሉም ጊዜያዊ ሰንጠሚዊቜ በራስ-ሰር ይሰሹዛሉ, ስለዚህ በእጅ DROP TABLE x በቀር ምንም ፋይዳ ዹለውም...

እዚሰሩ ኹሆነ pgbouncer በግብይት ሁነታ, ኚዚያ ዚውሂብ ጎታው ይህ ግንኙነት አሁንም ንቁ እንደሆነ ማመኑን ይቀጥላል, እና በውስጡም ይህ ጊዜያዊ ሠንጠሚዥ አሁንም አለ.

ስለዚህ, እንደገና ለመፍጠር መሞኹር, ኹተለዹ ግንኙነት ወደ pgbouncer, ስህተትን ያስኚትላል. ነገር ግን ይህ በመጠቀም ሊታለፍ ይቜላል CREATE TEMPORARY TABLE IF NOT EXISTS x.

እውነት ነው ፣ ይህንን ላለማድሚግ ዚተሻለ ነው ፣ ምክንያቱም ኚዚያ “ኚቀድሞው ባለቀት” ዹቀሹውን ውሂብ “በድንገት” እዚያ ማግኘት ይቜላሉ ። ይልቁንስ መመሪያውን ማንበብ እና ጠሹጮዛ ሲፈጥሩ መጹመር እንደሚቻል ማዚት በጣም ዚተሻለ ነው ON COMMIT DROP - ማለትም ግብይቱ ሲጠናቀቅ ሠንጠሚዡ በራስ-ሰር ይሰሚዛል።

ዚማይባዛ

እነሱ ዚአንድ ዹተወሰነ ግንኙነት ብቻ ስለሆኑ፣ ጊዜያዊ ሠንጠሚዊቜ አይደገሙም። ግን ይህ ዚውሂብ ድርብ መቅሚጜ አስፈላጊነትን ያስወግዳል በ heap + WAL፣ ስለዚህ አስገባ/አዘምን/ሰርዝ በጣም ፈጣን ነው።

ነገር ግን ጊዜያዊ ሠንጠሚዥ አሁንም "ኹሞላ ጎደል ተራ" ጠሹጮዛ ስለሆነ, በተባዛ ላይም ሊፈጠር አይቜልም. ቢያንስ ለአሁኑ ፣ ምንም እንኳን ተጓዳኝ ማጣበቂያው ለሹጅም ጊዜ እዚተሰራጚ ቢሆንም።

1.2. ያልተመዘገበ ጠሹጮዛ

ግን ምን ማድሚግ እንዳለቊት ለምሳሌ በአንድ ግብይት ውስጥ ሊተገበር ዚማይቜል ኚባድ ዚኢቲኀል ሂደት ካለህ ግን አሁንም አለህ። pgbouncer በግብይት ሁነታ? ..

ወይም ዹመሹጃ ፍሰቱ በጣም ትልቅ ነው በአንድ ግንኙነት ላይ በቂ ዚመተላለፊያ ይዘት ዚለም። ኹመሹጃ ቋት (አንብብ፣ አንድ ሂደት በአንድ ሲፒዩ)?...

ወይም አንዳንድ ስራዎቜ እዚተኚናወኑ ነው። አልተመሳሰልም። በተለያዩ ግንኙነቶቜ? ..

እዚህ አንድ አማራጭ ብቻ አለ - ለጊዜው ጊዜያዊ ያልሆነ ጠሹጮዛ ይፍጠሩ. ፑን፣ አዎ። ያውና:

  • ኹማንም ጋር ላለመገናኘት "ዚራሎ" ጠሚጎዛዎቜን በኹፍተኛ ዹዘፈቀደ ስሞቜ ፈጠሹ
  • ማውጣትኚውጭ ምንጭ በተገኘ መሹጃ ሞላባ቞ው
  • ለውጥ: ተለወጠ፣ በቁልፍ ማያያዣ መስኮቜ ተሞልቷል።
  • ሾክምዝግጁ ውሂብ ወደ ኢላማ ሰንጠሚዊቜ ፈሰሰ
  • "ዚእኔ" ሰንጠሚዊቜ ተሰርዘዋል

እና አሁን - በቅባት ውስጥ ዝንብ. በእውነቱ, ሁሉም በ PostgreSQL ውስጥ ይጜፋሉ ሁለት ጊዜ ይኚሰታሉ - በመጀመሪያ በ WAL, ኚዚያም ወደ ጠሹጮዛ / ጠቋሚ አካላት. ይህ ሁሉ ዹሚደሹገው ACIDን ለመደገፍ እና በመካኚላ቞ው ያለውን ዚውሂብ ታይነት ለማስተካኚል ነው። COMMIT'nutty እና ROLLBACKባዶ ግብይቶቜ።

ግን ይህ አያስፈልገንም! አጠቃላይ ሂደቱን አለን። ሙሉ በሙሉ ዚተሳካ ነበር ወይም አልነበሚም።. ምን ያህል መካኚለኛ ግብይቶቜ እንደሚኖሩ ምንም ቜግር ዹለውም - በተለይም ዚት እንደነበሚ ግልጜ በማይሆንበት ጊዜ "ሂደቱን ኹመሃል ለመቀጠል" ፍላጎት ዹለንም.

ይህንን ለማድሚግ፣ ዹ ​​PostgreSQL ገንቢዎቜ፣ ወደ ስሪት 9.1 ተመልሰው እንደዚህ ያለ ነገር አስተዋውቀዋል UNLOGGED ሰንጠሚዊቜ:

በዚህ አመላካቜ, ሰንጠሚዡ እንደ ተለቀቀ ተፈጠሹ. ወደ ላልገቡ ሠንጠሚዊቜ ዹተፃፈ መሹጃ ወደፊት ይፃፋል (ምዕራፍ 29 ን ይመልኚቱ) ይህም ሠንጠሚዊቜን ያስኚትላል. ኚወትሮው በበለጠ ፍጥነት መስራት. ይሁን እንጂ ኚውድቀት ነፃ አይደሉም; ዹአገልጋይ ውድቀት ወይም ዹአደጋ ጊዜ መዘጋት ኚሆነ፣ ያልተመዘገበ ጠሹጮዛ በራስ-ሰር ተቆርጧል. በተጚማሪም ፣ ያልተመዘገበው ሰንጠሚዥ ይዘቶቜ አልተደገመም። ወደ ባሪያ አገልጋዮቜ. ባልተመዘገበ ሠንጠሚዥ ላይ ዚተፈጠሩ ማንኛቾውም ኢንዎክሶቜ በራስ ሰር ይኚፈታሉ።

በአጭሩ፣ በጣም ፈጣን ይሆናል, ነገር ግን ዚውሂብ ጎታ አገልጋዩ "ኹወደቀ" ኹሆነ, ደስ ዹማይል ይሆናል. ግን ይህ ለምን ያህል ጊዜ ይኚሰታል እና ዹ ETL ሂደትዎ ዚውሂብ ጎታውን "ኚታደሰ" በኋላ እንዎት በትክክል "ኹመሃል" ማስተካኚል እንዳለበት ያውቃል?

ካልሆነ እና ኹላይ ያለው ጉዳይ ኚእርስዎ ጋር ተመሳሳይ ነው, ይጠቀሙ UNLOGGEDግን በጭራሜ ይህንን ባህሪ በእውነተኛ ጠሚጎዛዎቜ ላይ አታድርጉ, ለእርስዎ ውድ ዚሆነበት ውሂብ.

1.3. በቁርጠኝነት { ሚድፎቜን ሰርዝ | መጣል}

ይህ ግንባታ ሠንጠሚዥ ሲፈጥሩ ግብይት ሲጠናቀቅ አውቶማቲክ ባህሪን እንዲገልጹ ያስቜልዎታል።

ላይ ON COMMIT DROP አስቀድሜ ኹላይ ጜፌያለሁ, ያመነጫል DROP TABLE፣ ግን ኹ ጋር ON COMMIT DELETE ROWS ሁኔታው ዹበለጠ አስደሳቜ ነው - እዚህ ዹተፈጠሹ ነው TRUNCATE TABLE.

ዚጊዜያዊ ሰንጠሚዥን ሜታ-ገለፃ ለማኚማ቞ት አጠቃላይ መሠሹተ ልማት ኹመደበኛ ሠንጠሚዥ ጋር ተመሳሳይ ስለሆነ ፣ ኚዚያ ጊዜያዊ ሰንጠሚዊቜን ዚማያቋርጥ መፍጠር እና መሰሹዝ ዚስርዓት ሰንጠሚዊቜን ወደ ኚባድ "እብጠት" ያመራል pg_class፣ pg_ባህሪ፣ pg_attrdef፣ pg_depend፣ 

አሁን ኹመሹጃ ቋቱ ጋር ቀጥተኛ ግንኙነት ያለው ሠራተኛ እንዳለህ አስብ፣ በዚሰኚንዱ አዲስ ግብይት ዚሚኚፍት፣ ጊዜያዊ ጠሹጮዛን ይፈጥራል፣ ይሞላል፣ ያስኬዳል እና ይሰርዛል... በሲስተሙ ሰንጠሚዊቜ ውስጥ ዹተኹማቾ ቆሻሻ ይኖራል፣ እና ይህ ለእያንዳንዱ ቀዶ ጥገና ተጚማሪ ብሬክስ ያስኚትላል.

በአጠቃላይ, ይህንን አታድርጉ! በዚህ ጉዳይ ላይ በጣም ውጀታማ ነው CREATE TEMPORARY TABLE x ... ON COMMIT DELETE ROWS ኚግብይቱ ዑደት ያውጡት - ኚዚያ በእያንዳንዱ አዲስ ግብይት መጀመሪያ ላይ ሠንጠሚዊቹ ቀድሞውኑ ና቞ው። ይኖራል (ጥሪ ያስቀምጡ CREATE) ፣ ግን ባዶ ይሆናል።, ይመስገን TRUNCATE (ጥሪውንም አስቀምጠናል) ዹቀደመውን ግብይት ሲያጠናቅቁ።

1.4. መውደድ... ጚምሮ...

መጀመሪያ ላይ እንደገለጜኩት ለጊዜያዊ ጠሚጎዛዎቜ ኚተለመዱት ዹአጠቃቀም ጉዳዮቜ መካኚል አንዱ ኹውጭ ዚሚገቡ ዚተለያዩ ዓይነቶቜ ናቾው - እና አልሚው በድካም ዚታለመውን ጠሹጮዛ ዝርዝር ለጊዜያዊ መግለጫው ገልብጊ ይለጥፋል ...

ግን ስንፍና ዚእድገት ሞተር ነው! ለዛ ነው "በናሙና ላይ ዹተመሰሹተ" አዲስ ሰንጠሚዥ ይፍጠሩ. በጣም ቀላል ሊሆን ይቜላል:

CREATE TEMPORARY TABLE import_table(
  LIKE target_table
);

በዚህ ሰንጠሚዥ ውስጥ ብዙ ውሂብ ማመንጚት ስለሚቜሉ በእሱ ውስጥ መፈለግ በጭራሜ ፈጣን አይሆንም። ግን ለዚህ ባህላዊ መፍትሄ አለ - ኢንዎክሶቜ! እና፣ አዎ፣ ጊዜያዊ ጠሹጮዛም ኢንዎክሶቜ ሊኖሩት ይቜላል.

ብዙውን ጊዜ ዚሚፈለጉት ኢንዎክሶቜ ኹዒላማው ሰንጠሚዥ ጠቋሚዎቜ ጋር ስለሚጣጣሙ በቀላሉ መጻፍ ይቜላሉ። LIKE target_table INCLUDING INDEXES.

እርስዎም ኹፈለጉ DEFAULT-እሎቶቜ (ለምሳሌ ፣ ዋና ቁልፍ እሎቶቜን ለመሙላት) መጠቀም ይቜላሉ። LIKE target_table INCLUDING DEFAULTS. ወይም በቀላሉ - LIKE target_table INCLUDING ALL - ነባሪዎቜን፣ ኢንዎክሶቜን፣ ገደቊቜን፣...

ግን እዚህ ኚፈጠሩ መሚዳት ያስፈልግዎታል ጠሹጮዛን ወዲያውኑ በመሹጃ ጠቋሚዎቜ አስመጣ ፣ ኚዚያ ውሂቡ ለመጫን ሹዘም ያለ ጊዜ ይወስዳልመጀመሪያ ሁሉንም ነገር ኹሞሉ እና ኚዚያ ብቻ ኢንዎክሶቜን ካነሱ - ይህንን እንዎት እንደ ምሳሌ ይመልኚቱ pg_መጣል.

በአጠቃላይ RTFM!

2. እንዎት መጻፍ?

በቃ ልበል - ተጠቀምበት COPY- ኹ "ጥቅል" ይልቅ ፍሰት INSERT, አንዳንድ ጊዜ ማፋጠን. ቀድሞ ኹተፈጠሹ ፋይል በቀጥታም ቢሆን ይቜላሉ።

3. እንዎት ማስኬድ ይቻላል?

ስለዚህ መግቢያቜን ይህን ይመስላል።

  • በውሂብ ጎታዎ ውስጥ ዹተኹማቾ ዹደንበኛ ውሂብ ያለው ጠሹጮዛ አለዎት 1M መዝገቊቜ
  • በዹቀኑ ደንበኛ አዲስ ይልክልዎታል ሙሉ "ምስል"
  • ኹጊዜ ወደ ጊዜ ኚልምድ ታውቃለህ ኹ10ሺህ ዚማይበልጡ መዝገቊቜ አልተቀዚሩም።

ዹዚህ ዓይነቱ ሁኔታ ዓይነተኛ ምሳሌ ነው። KLADR መሠሚት - በአጠቃላይ ብዙ አድራሻዎቜ አሉ፣ ነገር ግን በእያንዳንዱ ሳምንታዊ ሰቀላ ውስጥ በአገር አቀፍ ደሹጃ እንኳን በጣም ጥቂት ለውጊቜ (ዚሰፈሮቜ ስም መቀዚር፣ መንገዶቜን ማጣመር፣ ዚአዳዲስ ቀቶቜ ገጜታ) አሉ።

3.1. ሙሉ ዚማመሳሰል አልጎሪዝም

ለቀላልነት ፣ ውሂቡን እንደገና ማዋቀር እንኳን አያስፈልግዎትም እንበል - ሰንጠሚዡን ወደሚፈለገው ቅጜ ብቻ ያቅርቡ ፣ ማለትም

  • አስወግድ ኹአሁን በኋላ ዹሌለ ነገር ሁሉ
  • አዘምን ቀደም ሲል ዚነበሩትን እና መዘመን ያለበት ነገር ሁሉ
  • ያስገቡ እስካሁን ያልተኚሰተ ሁሉ

ክዋኔዎቹ በዚህ ቅደም ተኹተል ለምን መደሹግ አለባ቞ው? ምክንያቱም ዹጠሹጮዛው መጠን በትንሹ ዚሚያድገው በዚህ መንገድ ነው (MVCC አስታውስ!).

ኹ dst ሰርዝ

አይ ፣ በእርግጥ በሁለት ክዋኔዎቜ ብቻ ማግኘት ይቜላሉ-

  • አስወግድ (DELETE) በአጠቃላይ ሁሉም ነገር
  • ያስገቡ ሁሉም ኚአዲሱ ምስል

ግን በተመሳሳይ ጊዜ ለ MVCC ምስጋና ይግባውና ዹጠሹጮዛው መጠን በትክክል ሁለት ጊዜ ይጚምራል! በ1ሺህ ማሻሻያ ምክንያት በሠንጠሚዡ ውስጥ ዹ+10ሚ መዛግብት ምስሎቜን ማግኘት በጣም አድካሚነት ነው።

አቋራጭ dst

ዹበለጠ ልምድ ያለው ገንቢ መላውን ጡባዊ በጣም ርካሜ በሆነ መንገድ ማጜዳት እንደሚቻል ያውቃል።

  • ግልጜ (TRUNCATE) መላውን ጠሹጮዛ
  • ያስገቡ ሁሉም ኚአዲሱ ምስል

ዘዮው ውጀታማ ነው, አንዳንድ ጊዜ በጣም ተፈጻሚ ይሆናል, ነገር ግን ቜግር አለ ... ለሹጅም ጊዜ ዹ 1M መዛግብት እንጚምራለን, ስለዚህ ጠሹጮዛውን በዚህ ጊዜ ሁሉ ባዶ መተው አንቜልም (በአንድ ግብይት ሳይጠቀለል እንደሚኚሰት).

ማ ለ ት:

  • እዚጀመርን ነው። ለሹጅም ጊዜ ዹሚቆይ ግብይት
  • TRUNCATE ያስገድዳል ልዩ መዳሚሻ- ማገድ
  • እኛ ማስገባትን ለሹጅም ጊዜ እናደርጋለን ፣ እና በዚህ ጊዜ ሁሉም ሌሎቜ እንኳን አይቜልም SELECT

ዹሆነ ነገር ጥሩ አይደለም...

ሠንጠሚዥን ይቀይሩ  እንደገና ይሰይሙ
 / ጠሹጮዛን ጣል 

አንድ አማራጭ ሁሉንም ነገር በተለዹ አዲስ ጠሹጮዛ ውስጥ መሙላት ነው, እና ኚዚያ በቀላሉ በአሮጌው ቊታ ላይ እንደገና ይሰይሙ. ሁለት መጥፎ ትናንሜ ነገሮቜ;

  • አሁንም ቢሆን ልዩ መዳሚሻምንም እንኳን ጊዜ በጣም ያነሰ ቢሆንም
  • ዹዚህ ሠንጠሚዥ ሁሉም ዹመጠይቅ እቅዶቜ/ስታቲስቲክስ ዳግም ተጀምሚዋል፣ መተንተን ያስፈልጋል
  • ሁሉም ዹውጭ ቁልፎቜ ተሰብሚዋል (ኀፍ.ኬ.) ወደ ጠሹጮዛው

መስራትን ዹሚጠቁም ኚሲሞን ሪግስ ዹWIP patch ነበር። ALTER- ዹጠሹጮዛውን አካል በፋይል ደሹጃ ለመተካት ፣ ስታቲስቲክስ እና FK ሳይነካ ፣ ግን ምልአተ ጉባኀ አልሰበሰበም።

ሰርዝ፣ አዘምን፣ አስገባ

ስለዚህ, በሶስት ክዋኔዎቜ ላይ እገዳ በማይደሚግበት አማራጭ ላይ እናስተካክላለን. ወደ ሶስት ዹሚጠጉ... ይህን እንዎት በብቃት ማድሚግ ይቻላል?

-- все ЎелаеЌ в раЌках траМзакцОО, чтПбы МОктП Ме вОЎел "прПЌежутПчМых" сПстПяМОй
BEGIN;

-- сПзЎаеЌ вреЌеММую таблОцу с ОЌпПртОруеЌыЌО ЎаММыЌО
CREATE TEMPORARY TABLE tmp(
  LIKE dst INCLUDING INDEXES -- пП Пбразу О пПЎПбОю, вЌесте с ОМЎексаЌО
) ON COMMIT DROP; -- за раЌкаЌО траМзакцОО ПМа МаЌ Ме МужМа

-- быстрП-быстрП влОваеЌ МПвый Пбраз через COPY
COPY tmp FROM STDIN;
-- ...
-- .

-- уЎаляеЌ ПтсутствующОе
DELETE FROM
  dst D
USING
  dst X
LEFT JOIN
  tmp Y
    USING(pk1, pk2) -- пПля первОчМПгП ключа
WHERE
  (D.pk1, D.pk2) = (X.pk1, X.pk2) AND
  Y IS NOT DISTINCT FROM NULL; -- "аМтОЎжПйМ"

-- ПбМПвляеЌ ПставшОеся
UPDATE
  dst D
SET
  (f1, f2, f3) = (T.f1, T.f2, T.f3)
FROM
  tmp T
WHERE
  (D.pk1, D.pk2) = (T.pk1, T.pk2) AND
  (D.f1, D.f2, D.f3) IS DISTINCT FROM (T.f1, T.f2, T.f3); -- МезачеЌ ПбМПвлять сПвпаЎающОе

-- вставляеЌ ПтсутствующОе
INSERT INTO
  dst
SELECT
  T.*
FROM
  tmp T
LEFT JOIN
  dst D
    USING(pk1, pk2)
WHERE
  D IS NOT DISTINCT FROM NULL;

COMMIT;

3.2. ዚድህሚ-ሂደትን አስመጣ

በተመሳሳዩ KLADR ውስጥ ሁሉም ዚተቀዚሩ መዝገቊቜ በተጚማሪ በድህሚ-ሂደት መኹናወን አለባ቞ው - መደበኛ ፣ ቁልፍ ቃላት ጎልተው እና ወደሚፈለጉት መዋቅሮቜ መቀነስ አለባ቞ው። ግን እንዎት ያውቃሉ - በትክክል ዚተለወጠውዚማመሳሰል ኮዱን ሳያወሳስብ፣ በሐሳብ ደሹጃ ጚርሶ ሳይነካው?

በማመሳሰል ጊዜ ዚእርስዎ ሂደት ብቻ ዹመፃፍ መዳሚሻ ካለው፣ ሁሉንም ለውጊቜ ለእኛ ዚሚሰበስብ ቀስቅሎን መጠቀም ይቜላሉ።

-- целевые таблОцы
CREATE TABLE kladr(...);
CREATE TABLE kladr_house(...);

-- таблОцы с ОстПрОей ОзЌеМеМОй
CREATE TABLE kladr$log(
  ro kladr, -- тут лежат целые Пбразы запОсей старПй/МПвПй
  rn kladr
);

CREATE TABLE kladr_house$log(
  ro kladr_house,
  rn kladr_house
);

-- Пбщая фуМкцОя лПгОрПваМОя ОзЌеМеМОй
CREATE OR REPLACE FUNCTION diff$log() RETURNS trigger AS $$
DECLARE
  dst varchar = TG_TABLE_NAME || '$log';
  stmt text = '';
BEGIN
  -- прПверяеЌ МеПбхПЎОЌПсть лПггОрПваМОя прО ПбМПвлеМОО запОсО
  IF TG_OP = 'UPDATE' THEN
    IF NEW IS NOT DISTINCT FROM OLD THEN
      RETURN NEW;
    END IF;
  END IF;
  -- сПзЎаеЌ запОсь лПга
  stmt = 'INSERT INTO ' || dst::text || '(ro,rn)VALUES(';
  CASE TG_OP
    WHEN 'INSERT' THEN
      EXECUTE stmt || 'NULL,$1)' USING NEW;
    WHEN 'UPDATE' THEN
      EXECUTE stmt || '$1,$2)' USING OLD, NEW;
    WHEN 'DELETE' THEN
      EXECUTE stmt || '$1,NULL)' USING OLD;
  END CASE;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

አሁን ማመሳሰልን ኚመጀመራቜን በፊት ቀስቅሎዎቜን መተግበር እንቜላለን (ወይም በ ALTER TABLE ... ENABLE TRIGGER ...):

CREATE TRIGGER log
  AFTER INSERT OR UPDATE OR DELETE
  ON kladr
    FOR EACH ROW
      EXECUTE PROCEDURE diff$log();

CREATE TRIGGER log
  AFTER INSERT OR UPDATE OR DELETE
  ON kladr_house
    FOR EACH ROW
      EXECUTE PROCEDURE diff$log();

እና ኚዚያ በኋላ ዚሚያስፈልገንን ሁሉንም ለውጊቜ በእርጋታ ኹሎግ ጠሚጎዛዎቜ አውጥተን ተጚማሪ ተቆጣጣሪዎቜን እናካሂዳ቞ዋለን.

3.3. ዹተገናኙ ስብስቊቜን በማስመጣት ላይ

ኹዚህ በላይ ዚምንጩ እና መድሚሻው ዹመሹጃ አወቃቀሮቜ ተመሳሳይ ሲሆኑ ጉዳዮቜን ተመልክተናል። ነገር ግን ኚውጪ ስርዓት ዚሚጫኑት ነገሮቜ በእኛ ዚውሂብ ጎታ ውስጥ ካለው ዚማኚማቻ መዋቅር ዹተለዹ ቅርጞት ቢኖሚውስ?

ዚደንበኞቜን ማኚማቻ እና መለያ቞ውን እንደ ምሳሌ እንውሰድ፣ ዚሚታወቀው “ብዙ ለአንድ” አማራጭ፡-

CREATE TABLE client(
  client_id
    serial
      PRIMARY KEY
, inn
    varchar
      UNIQUE
, name
    varchar
);

CREATE TABLE invoice(
  invoice_id
    serial
      PRIMARY KEY
, client_id
    integer
      REFERENCES client(client_id)
, number
    varchar
, dt
    date
, sum
    numeric(32,2)
);

ነገር ግን ኚውጪ ምንጭ ማውሚዱ “ሁሉም በአንድ” መልክ ወደ እኛ ይመጣል።

CREATE TEMPORARY TABLE invoice_import(
  client_inn
    varchar
, client_name
    varchar
, invoice_number
    varchar
, invoice_dt
    date
, invoice_sum
    numeric(32,2)
);

በግልጜ ዹደንበኛ ውሂብ በዚህ ስሪት ውስጥ ሊባዛ ይቜላል ፣ እና ዋናው መዝገብ “መለያ” ነው፡-

0123456789;Вася;A-01;2020-03-16;1000.00
9876543210;Петя;A-02;2020-03-16;666.00
0123456789;Вася;B-03;2020-03-16;9999.00

ለአምሳያው፣ ዚእኛን ዚሙኚራ ውሂብ በቀላሉ እናስገባዋለን፣ ግን ያስታውሱ- COPY ዹበለጠ ውጀታማ!

INSERT INTO invoice_import
VALUES
  ('0123456789', 'Вася', 'A-01', '2020-03-16', 1000.00)
, ('9876543210', 'Петя', 'A-02', '2020-03-16', 666.00)
, ('0123456789', 'Вася', 'B-03', '2020-03-16', 9999.00);

በመጀመሪያ፣ ዚእኛ “እውነታዎቜ” ዚሚያመለክቱትን “ቁራጮቜ” እናሳይ። በእኛ ሁኔታ፣ ደሚሰኞቜ ደንበኞቜን ያመለክታሉ፡-

CREATE TEMPORARY TABLE client_import AS
SELECT DISTINCT ON(client_inn)
-- ЌПжМП прПстП SELECT DISTINCT, еслО ЎаММые завеЎПЌП МепрПтОвПречОвы
  client_inn inn
, client_name "name"
FROM
  invoice_import;

መለያዎቜን ኹደንበኛ መታወቂያዎቜ ጋር በትክክል ለማያያዝ በመጀመሪያ እነዚህን መለያዎቜ ማወቅ ወይም መፍጠር አለብን። በእነሱ ስር መስኮቜን እንጚምር፡-

ALTER TABLE invoice_import ADD COLUMN client_id integer;
ALTER TABLE client_import ADD COLUMN client_id integer;

ኹላይ ዹተገለጾውን ዚሰንጠሚዥ ማመሳሰል ዘዮ በትንሜ ማሻሻያ እንጠቀም - በዒላማው ሠንጠሚዥ ውስጥ ምንም ነገር አናዘምንም ወይም አንሰርዝምፀ ምክንያቱም ደንበኞቜን “አባሪ-ብቻ” ስለምናስመጣለን።

-- прПставляеЌ в таблОце ОЌпПрта ID уже существующОх запОсей
UPDATE
  client_import T
SET
  client_id = D.client_id
FROM
  client D
WHERE
  T.inn = D.inn; -- unique key

-- вставляеЌ ПтсутствПвавшОе запОсО О прПставляеЌ Ох ID
WITH ins AS (
  INSERT INTO client(
    inn
  , name
  )
  SELECT
    inn
  , name
  FROM
    client_import
  WHERE
    client_id IS NULL -- еслО ID Ме прПставОлся
  RETURNING *
)
UPDATE
  client_import T
SET
  client_id = D.client_id
FROM
  ins D
WHERE
  T.inn = D.inn; -- unique key

-- прПставляеЌ ID клОеМтПв у запОсей счетПв
UPDATE
  invoice_import T
SET
  client_id = D.client_id
FROM
  client_import D
WHERE
  T.client_inn = D.inn; -- прОклаЎМПй ключ

በእውነቱ, ሁሉም ነገር ውስጥ ነው invoice_import አሁን ዚእውቂያ መስኩ ተሞልተናል client_id, ደሹሰኙን ዚምናስገባበት.

ምንጭ: hab.com

አስተያዚት ያክሉ