Skip to content

فصل ۹ — بازآرایی‌های معماری (Architectural Refactorings)

بازآرایی‌های معماری تغییراتی هستند که نحوهٔ کلی تعامل برنامه‌های بیرونی با پایگاه داده را بهبود می‌دهند. بازآرایی‌های معماری عبارت‌اند از:

  • Add CRUD Methods
  • Add Mirror Table
  • Add Read Method
  • Encapsulate Table With View
  • Introduce Calculation Method
  • Introduce Index
  • Introduce Read-Only Table
  • Migrate Method From Database
  • Migrate Method To Database
  • Replace Method(s) With View
  • Replace View With Method(s)
  • Use Official Data Source

Add CRUD Methods — افزودن متدهای CRUD

چهار stored procedure (متد) برای پیاده‌سازی ایجاد، بازیابی، به‌روزرسانی و حذف (CRUD) داده‌ای که یک موجودیت کسب‌وکار را نمایش می‌دهد معرفی کنید. پس از قرار گرفتن این stored procedureها، دسترسی به جداول منبع فقط به این procedureها و مدیران محدود می‌شود.

انگیزه (Motivation)

چند دلیل برای اعمال Add CRUD Methods وجود دارد:

  • کپسوله‌سازی دسترسی به داده. Stored procedureها راه رایجی برای کپسوله‌سازی دسترسی به پایگاه داده هستند، هرچند به‌اندازهٔ چارچوب‌های persistence مؤثر نیستند (فصل ۱، «توسعهٔ تکاملی پایگاه داده» را ببینید).
  • جداسازی کد برنامه از جداول پایگاه داده. Stored procedureها راه مؤثری برای جداسازی برنامه‌ها از جداول پایگاه داده هستند. آن‌ها امکان تغییر جداول بدون تغییر کد برنامه را فراهم می‌کنند.
  • پیاده‌سازی کنترل دسترسی امنیتی (SAC) در سطح موجودیت. به‌جای دسترسی مستقیم به جداول منبع، برنامه‌ها stored procedureهای مربوط را فراخوانی می‌کنند. Stored procedureهای CRUD راهی برای پیاده‌سازی SAC در سطح موجودیت فراهم می‌کنند. محصولات پایگاه داده معمولاً SAC داده را در سطح جدول، ستون و گاهی ردیف پیاده‌سازی می‌کنند. اما وقتی دادهٔ موجودیت‌های پیچیدهٔ کسب‌وکار مانند Customer در چند جدول ذخیره می‌شود، SAC در سطح موجودیت اگر فقط به SAC داده‌محور محدود شوید می‌تواند بسیار پیچیده شود. خوشبختانه بیشتر محصولات پایگاه داده SAC متد را هم پیاده‌سازی می‌کنند و بنابراین می‌توانید SAC در سطح موجودیت را از طریق متدهای CRUD پیاده‌سازی کنید.

معاوضه‌های بالقوه (Potential Tradeoffs)

مزیت اصلی کپسوله‌سازی دسترسی به پایگاه داده به این شکل این است که بازآرایی طرحوارهٔ جدول را آسان‌تر می‌کند. هنگام پیاده‌سازی بازآرایی‌های رایج طرحواره مانند Rename Table (صفحهٔ ۱۱۳)، Move Column (صفحهٔ ۱۰۳) و Split Column (صفحهٔ ۱۴۰)، باید فقط متدهای CRUD متناظر را بازآرایی کنید (به‌فرض اینکه هیچ برنامهٔ بیرونی دیگری مستقیماً به طرحوارهٔ جدول دسترسی نداشته باشد).

متأسفانه این رویکرد کپسوله‌سازی پایگاه داده هزینه‌ای دارد. متدها (stored procedure، stored function و trigger) مختص فروشندهٔ پایگاه داده هستند — مثلاً متدهای Oracle به‌راحتی به Sybase قابل انتقال نیستند. علاوه بر این، تضمینی نیست که متدهایی که در یک نسخه از پایگاه داده کار می‌کنند به‌راحتی به نسخهٔ جدیدتر منتقل شوند؛ بنابراین ممکن است بار ارتقا را هم افزایش دهید. مسئلهٔ دیگر فقدان انعطاف است. اگر بخواهید به بخشی از یک موجودیت کسب‌وکار دسترسی داشته باشید چه؟ آیا واقعاً هر بار می‌خواهید با همهٔ داده‌های موجودیت کار کنید یا شاید متدهای CRUD برای آن زیرموجودیت معرفی کنید؟ اگر به داده‌ای که از چند موجودیت عبور می‌کند نیاز دارید — شاید برای گزارش — چه؟ چند stored procedure را برای خواندن هر موجودیت کسب‌وکار فراخوانی می‌کنید و سپس دادهٔ موردنیاز را انتخاب می‌کنید، یا Add Read Method (صفحهٔ ۲۴۰) را برای بازیابی دادهٔ خاص موردنیاز گزارش اعمال می‌کنید؟

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

برای به‌روزرسانی طرحوارهٔ پایگاه داده باید موارد زیر را انجام دهید:

  1. دادهٔ کسب‌وکار را شناسایی کنید. باید موجودیت کسب‌وکار — مانند Customer در شکل ۹.۱ — را که می‌خواهید متدهای CRUD برای آن پیاده‌سازی کنید شناسایی کنید. پس از دانستن موجودیت مورد کپسوله‌سازی، باید دادهٔ منبع آن موجودیت در پایگاه داده را شناسایی کنید.

  2. Stored procedureها را بنویسید. باید حداقل چهار stored procedure بنویسید: یکی برای ایجاد موجودیت، یکی برای خواندن آن بر اساس کلید اصلی، یکی برای به‌روزرسانی موجودیت و یکی برای حذف آن. Stored procedureهای اضافی برای بازیابی موجودیت به روش‌هایی غیر از کلید اصلی را می‌توان با اعمال بازآرایی Add Read Method (صفحهٔ ۲۴۰) اضافه کرد.

  3. Stored procedureها را تست کنید. یکی از بهترین روش‌های کار، رویکرد توسعهٔ تست‌اول (TDD) است؛ فصل ۱، «توسعهٔ تکاملی پایگاه داده» را ببینید.

شکل ۹.۱. افزودن متدهای CRUD برای Customer.

شکل ۹.۱ نحوهٔ معرفی متدهای CRUD برای موجودیت Customer را نشان می‌دهد. کد ReadCustomer در اینجا آمده است. کد سایر stored procedureها خودگویاست:

sql
CREATE OR REPLACE PACKAGE CustomerCRUD AS
    TYPE customerType IS REF CURSOR RETURN
    Customer%ROWTYPE;
    PROCEDURE ReadCustomer
      (readCustomerId IN NUMBER,customers OUT
      customerType);
    PROCEDURE CreateCustomer(....);
    PROCEDURE UpdateCustomer(....);
    PROCEDURE DeleteCustomer(....);
    END CustomerCRUD;
    /

    CREATE OR REPLACE PACKAGE BODY CustomerCRUD AS

    PROCEDURE ReadCustomer
      (readCustomerId IN NUMBER,customerReturn OUT

      customerType) IS
    BEGIN
    OPEN refCustomer FOR
      SELECT * FROM Customer WHERE CustomerID =
      readCustomerId;
    END ReadCustomer;

     END CustomerCRUD;
/

قراردادهای نام‌گذاری

متدهای CRUD باید از قرارداد نام‌گذاری مشترکی پیروی کنند تا خوانایی بهتر شود. ما قالب CreateCustomer، ReadCustomer، UpdateCustomer و DeleteCustomer نشان‌داده‌شده در شکل ۹.۱ را ترجیح می‌دهیم — هرچند CustomerCreate، CustomerRead، CustomerUpdate و CustomerDelete هم منطقی‌اند. یک رویکرد را انتخاب کنید و به آن پایبند بمانید.

مکانیک مهاجرت داده (Data-Migration Mechanics)

برای این بازآرایی پایگاه داده داده‌ای برای مهاجرت وجود ندارد.

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

هنگام معرفی متدهای CRUD، باید همهٔ جاهایی در برنامه‌های بیرونی که موجودیت فعلاً استفاده می‌شود را شناسایی کنید و سپس آن کد را برای فراخوانی stored procedureهای جدید بازآرایی کنید. ممکن است کشف کنید برنامه‌های مختلف زیرمجموعه‌های متفاوتی از داده نیاز دارند — یا از زاویهٔ دیگر، برخی برنامه‌ها کمی بیشتر از بقیه به داده نیاز دارند. ممکن است کشف کنید باید Add CRUD Methods را هم‌زمان برای چند موجودیت اعمال کنید؛ احتمالاً تغییر بزرگی است.

مثال کد اول نشان می‌دهد کلاس Customer در Java در ابتدا SQL سخت‌کدشده را برای بازیابی داده به پایگاه داده ارسال می‌کرد. مثال دوم نشان می‌دهد چگونه برای فراخوانی stored procedure بازآرایی می‌شود:

java
// Before code
stmt.prepare(
  "SELECT FirstName, Surname, PhoneNumber FROM
  Customer " +
    "WHERE CustomerId=?");
stmt.setLong(1,customerId);
stmt.execute();
ResultSet rs = stmt.executeQuery();

//After code
stmt = conn.prepareCall("begin ? := ReadCustomer(?); end;");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
stmt.setLong(2, customerId);
stmt.execute();
ResultSet rs = stmt.getObject(1);

Add Mirror Table — افزودن جدول آینه‌ای

یک جدول آینه‌ای — کپی دقیق یک جدول موجود در یک پایگاه داده — در پایگاه دادهٔ دیگر ایجاد کنید.

انگیزه (Motivation)

چند دلیل برای اعمال Add Mirror Table وجود دارد:

  • بهبود عملکرد پرس‌وجو. پرس‌وجوی مجموعه‌ای از جداول ممکن است به‌دلیل دور بودن پایگاه داده کند باشد؛ بنابراین جدول ازپیش‌پرشده روی سرور محلی ممکن است عملکرد کلی را بهبود دهد.
  • ایجاد دادهٔ افزون. بسیاری از برنامه‌ها داده را به‌صورت بلادرنگ از پایگاه‌های دادهٔ دیگر پرس‌وجو می‌کنند. جدولی حاوی این داده در پایگاه دادهٔ محلی وابستگی شما به آن پایگاه(های) داده را کاهش می‌دهد و بافری برای زمانی که آن‌ها از کار می‌افتند یا برای نگهداری خارج از سرویس می‌شوند فراهم می‌کند.
  • جایگزینی خواندن‌های افزون. چند برنامهٔ بیرونی — یا stored procedure — اغلب همان پرس‌وجوی بازیابی را پیاده‌سازی می‌کنند. این پرس‌وجوها به پایگاه دادهٔ دور را می‌توان با جدول آینه‌ای روی پایگاه دادهٔ محلی که با پایگاه دادهٔ دور همگام می‌شود جایگزین کرد.

معاوضه‌های بالقوه (Potential Tradeoffs)

چالش اصلی هنگام معرفی جدول آینه‌ای «دادهٔ کهنه» (stale data) است. دادهٔ کهنه وقتی رخ می‌دهد که یک جدول به‌روز شود اما دیگری نشود — به‌یاد داشته باشید هر یک از جدول منبع یا آینه ممکن است به‌روز شود. این مشکل با ایجاد آینه‌های بیشتر از Customer در پایگاه‌های دادهٔ دیگر افزایش می‌یابد. همان‌طور که در شکل ۹.۲ می‌بینید، باید نوعی راهبرد همگام‌سازی پیاده‌سازی کنید.

شکل ۹.۲. افزودن جدول آینه‌ای Customer.

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

همان‌طور که در شکل ۹.۲ نشان داده شده، برای به‌روزرسانی طرحوارهٔ پایگاه داده هنگام انجام Add Mirror Table باید موارد زیر را انجام دهید:

  1. مکان را تعیین کنید. باید تصمیم بگیرید جدول آینه‌ای Customer کجا قرار می‌گیرد — در این مثال آن را در DesktopDB آینه می‌کنیم.
  2. جدول آینه‌ای را معرفی کنید. DesktopDB.Customer را در پایگاه دادهٔ دیگر با دستور CREATE TABLE در SQL ایجاد کنید.
  3. راهبرد همگام‌سازی را تعیین کنید. رویکرد بلادرنگ شکل ۹.۲ باید وقتی کاربران نهایی به اطلاعات به‌روز نیاز دارند اتخاذ شود.
  4. به‌روزرسانی را مجاز کنید. اگر می‌خواهید به‌روزرسانی DesktopDB.Customer مجاز باشد، باید راهی برای همگام‌سازی داده از DesktopDB.Customer به Customer فراهم کنید. DesktopDB.Customer قابل‌به‌روزرسانی به‌عنوان آینهٔ همتا به همتا (peer-to-peer) شناخته می‌شود؛ همچنین آینهٔ اصلی/فرعی (master/slave) نامیده می‌شود.

کد زیر DDL معرفی جدول DesktopDB.Customer را نشان می‌دهد:

sql
CREATE TABLE Customer (
   CustomerID NUMBER NOT NULL,
   Name VARCHAR(40),
   PhoneNumber VARCHAR2(40),
   CONSTRAINT PKCustomer
     PRIMARY KEY (CustomerID)
);

COMMENT ON Customer "Mirror table of Customer on Remote Location"

مکانیک مهاجرت داده (Data-Migration Mechanics)

باید ابتدا همهٔ دادهٔ منبع مربوط را به جدول آینه‌ای کپی کنید و سپس راهبرد همگام‌سازی (به‌روزرسانی بلادرنگ یا استفاده از replication پایگاه داده) را اعمال کنید. چند راهبرد پیاده‌سازی برای همگام‌سازی وجود دارد:

  1. تازه‌سازی دوره‌ای. از job زمان‌بندی‌شده‌ای استفاده کنید که جدول Customer و DesktopDB.Customer را همگام می‌کند. job باید بتواند با تغییرات داده در هر دو جدول کار کند و داده را دوطرفه به‌روز کند. تازه‌سازی دوره‌ای معمولاً هنگام ساخت انبار داده و data mart بهتر است.
  2. Replication پایگاه داده. محصولات پایگاه داده قابلیتی دارند که جداول را دوطرفه — multimaster replication — تکرار می‌کنند. پایگاه داده هر دو جدول را همگام نگه می‌دارد. به‌طور کلی وقتی می‌خواهید Customer و DesktopDB.Customer توسط کاربران قابل‌به‌روزرسانی باشند از این رویکرد استفاده می‌کنید. اگر محصول پایگاه داده این قابلیت را دارد، بهتر است از آن به‌جای راه‌حل‌های سفارشی استفاده کنید.
  3. همگام‌سازی مبتنی بر trigger. Trigger روی Customer ایجاد کنید تا تغییرات دادهٔ منبع به DesktopDB.Customer منتقل شود و trigger روی DesktopDB.Customer تا تغییرات جدول به Customer منتقل شود. این تکنیک امکان کدنویسی سفارشی همگام‌سازی داده را می‌دهد — مطلوب وقتی اشیای دادهٔ پیچیده باید همگام شوند؛ اما باید همهٔ triggerها را بنویسید که می‌تواند زمان‌بر باشد.

کد زیر نحوهٔ همگام‌سازی داده در جدول ProductionDB.Customer و DesktopDB.Customer با trigger را نشان می‌دهد:

sql
CREATE OR REPLACE TRIGGER
  UpdateCustomerMirror
  AFTER UPDATE OR INSERT OR DELETE
  ON Customer
  REFERENCING OLD AS OLD NEW AS NEW
  FOR EACH ROW
    DECLARE
      BEGIN
        IF DELETING THEN
           DeleteCustomerMirror;
        END IF;
        IF (UPDATING OR INSERTING) THEN
           UpdateCustomerMirror;
        END IF;
      END;
   END;
   /

CREATE OR REPLACE TRIGGER
  UpdateCustomer
  AFTER UPDATE OR INSERT OR DELETE
  ON CustomerMirror
  REFERENCING OLD AS OLD NEW AS NEW
  FOR EACH ROW
  DECLARE
  BEGIN
     IF DELETING THEN
       DeleteCustomer;
    END IF;
     IF (UPDATING OR INSERTING) THEN
       UpdateCustomer;
    END IF;
  END;
END;

/

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

قبلاً تحلیل کرده‌اید چرا DesktopDB.Customer را معرفی می‌کنید. مثلاً اگر Customer را روی پایگاه دادهٔ دور برای دسترسی آسان روی پایگاه دادهٔ محلی آینه می‌کنید، باید مطمئن شوید برنامه هنگام پرس‌وجوی جدول Customer به این پایگاه دادهٔ محلی متصل می‌شود نه پایگاه دادهٔ تولید. همچنین می‌توانید ویژگی‌های اتصال جایگزین تنظیم کنید که استفاده از DesktopDB یا ProductionDB برای پرس‌وجوی داده را ممکن کند:

java
// Before code
stmt = remoteDB.prepare("select
CustomerID,Name,PhoneNumber FROM Customer WHERE
CustomerID = ?");
stmt.setLong(1, customerID);
stmt.execute();
ResultSet rs = stmt.executeQuery();

//After code
stmt = localDB.prepare("select
CustomerID,Name,PhoneNumber FROM Customer WHERE
CustomerID = ?");
stmt.setLong(1, customerID);
stmt.execute();
ResultSet rs = stmt.executeQuery();

Add Read Method — افزودن متد خواندن

یک متد — در این مورد یک stored procedure — برای پیاده‌سازی بازیابی داده‌ای که صفر یا بیشتر موجودیت کسب‌وکار را از پایگاه داده نمایش می‌دهد معرفی کنید.

انگیزه (Motivation)

دلیل اصلی اعمال Add Read Method کپسوله‌سازی منطق لازم برای بازیابی دادهٔ خاص از پایگاه داده مطابق معیارهای تعریف‌شده است. متد — اغلب stored procedure — ممکن است لازم باشد یک یا چند عبارت SELECT پیاده‌سازی‌شده در کد برنامه و/یا گزارش‌گیری را جایگزین کند. انگیزهٔ رایج دیگر پیاده‌سازی راهبرد جستجوی یکنواخت برای یک موجودیت کسب‌وکار است.

گاهی این بازآرایی برای پشتیبانی از Introduce Soft Delete (صفحهٔ ۲۲۲) یا Introduce Hard Delete (صفحهٔ ۲۱۹) اعمال می‌شود. وقتی هر یک از این بازآرایی‌ها اعمال می‌شود، نحوهٔ حذف داده تغییر می‌کند — یا ردیف را به‌عنوان حذف‌شده علامت می‌زنید یا داده را فیزیکی حذف می‌کنید. چنین تغییر راهبردی ممکن است نیاز به تغییرات متعدد در برنامه‌ها داشته باشد تا بازیابی‌ها درست انجام شوند. با کپسوله‌سازی بازیابی داده در stored procedure و فراخوانی مناسب آن، پیاده‌سازی این دو بازآرایی بسیار آسان‌تر می‌شود چون منطق بازیابی لازم فقط در یک جا (stored procedure) بازکار می‌شود.

معاوضه‌های بالقوه (Potential Tradeoffs)

مزیت اصلی کپسوله‌سازی منطق بازیابی به این شکل — اغلب همراه با Add CRUD Methods (صفحهٔ ۲۳۲) — این است که بازآرایی طرحوارهٔ جدول را آسان‌تر می‌کند. متأسفانه این رویکرد کپسوله‌سازی پایگاه داده هزینه‌ای دارد. Stored procedureها مختص فروشندهٔ پایگاه داده هستند و قابلیت انتقال را کاهش می‌دهند؛ و اگر بد نوشته شوند ممکن است عملکرد کلی را کاهش دهند.

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

برای به‌روزرسانی طرحوارهٔ پایگاه داده باید موارد زیر را انجام دهید:

  1. داده را شناسایی کنید. باید داده‌ای که می‌خواهید بازیابی کنید را شناسایی کنید؛ ممکن است از چند جدول بیاید.
  2. معیارها را شناسایی کنید. چگونه می‌خواهید زیرمجموعهٔ داده برای بازیابی را مشخص کنید؟ مثلاً آیا می‌خواهید اطلاعات حساب‌های بانکی با موجودی بالاتر از مبلغ مشخص، یا افتتاح‌شده در شعبهٔ خاص، یا دسترسی‌یافته در بازهٔ زمانی مشخص — یا ترکیبی از این‌ها — را بازیابی کنید؟ توجه کنید معیارها ممکن است شامل کلید اصلی باشند یا نباشند.
  3. Stored procedure را بنویسید و تست کنید. ما به نوشتن مجموعهٔ تست رگرسیون کامل ۱۰۰ درصدی برای stored procedureها معتقدیم. بهتر از آن، رویکرد توسعهٔ تست‌اول (TDD) را توصیه می‌کنیم — ابتدا تست بنویسید و سپس کمی کد در stored procedureها (Astels 2003؛ Beck 2003).

شکل ۹.۳. افزودن متد خواندن Customer.

شکل ۹.۳ نحوهٔ معرفی stored procedure خواندن برای موجودیت Customer را نشان می‌دهد که نام و نام‌خانوادگی را به‌عنوان پارامتر می‌گیرد. کد stored procedure Read-Customer در زیر آمده است. فرض شده پارامترهایی مانند S% و Ambler به آن ارسال شود و همهٔ افراد با نام‌خانوادگی Ambler که نام کوچکشان با حرف S شروع می‌شود برگردانده شوند.

sql
PROCEDURE ReadCustomer
  (
  firstNameToFind IN VARCHAR,
  lastNameToFind IN VARCHAR,
  customerRecords OUT CustomerREF
) IS
BEGIN
OPEN refCustomer FOR
  SELECT * FROM Customer WHERE
  Customer.FirstName = firstNameToFind
  AND Customer.LastName = lastNameToFind;
END ReadCustomer;
/

مکانیک مهاجرت داده (Data-Migration Mechanics)

برای این بازآرایی پایگاه داده داده‌ای برای مهاجرت وجود ندارد.

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

هنگام معرفی stored procedure، باید همهٔ جاهایی در برنامه‌های بیرونی که داده خوانده می‌شود را شناسایی کنید و سپس آن کد را برای فراخوانی stored procedure جدید بازآرایی کنید. ممکن است کشف کنید برنامه‌های مختلف زیرمجموعه‌های متفاوتی از داده نیاز دارند و بنابراین شاید چند بار Add Read Method لازم باشد — یک بار برای هر مجموعهٔ اصلی عناصر داده.

در کد زیر، برنامه‌ها عبارت‌های SELECT را برای بازیابی اطلاعات مشتری به پایگاه داده ارسال می‌کردند؛ اما پس از بازآرایی فقط stored procedure را فراخوانی می‌کنند:

java
// Before code
stmt.prepare(

  "SELECT * FROM Customer" +
    "WHERE Customer.FirstName=? AND
    Customer.LastName=?");
stmt.setString(1,firstNameToFind);
stmt.setString(2,lastNameToFind);
stmt.execute();
ResultSet rs = stmt.executeQuery();

//After code
stmt = conn.prepareCall("begin ? := ReadCustomer(?,?,?); end;");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
stmt.setString(2, firstNameToFind);
stmt.setString(3,lastNameToFind);
stmt.execute();
ResultSet rs = stmt.getObject(1);
while (rs.next()) {
  getCustomerInformation(rs);
}

Encapsulate Table With View — کپسوله‌سازی جدول با نما

دسترسی به یک جدول موجود را با یک view بپوشانید.

انگیزه (Motivation)

دو دلیل برای اعمال Encapsulate Table With View وجود دارد. اول، پیاده‌سازی façade دور یک جدول موجود که قصد دارید بعداً بازآرایی کنید. با نوشتن برنامه‌ها برای دسترسی به دادهٔ منبع از طریق view به‌جای مستقیم از جداول، وابستگی مستقیم به جدول را کاهش می‌دهید و بازآرایی را آسان‌تر می‌کنید. مثلاً ممکن است بخواهید قبل از اعمال بازآرایی‌هایی مانند Rename Column (صفحهٔ ۱۰۹) یا Drop Column (صفحهٔ ۷۲) ابتدا دسترسی به جدول را از طریق view کپسوله کنید.

دوم، ممکن است بخواهید راهبرد کنترل دسترسی امنیتی (SAC) برای پایگاه داده پیاده‌سازی کنید. این کار را با کپسوله‌سازی دسترسی به جدول از طریق چند view و سپس محدود کردن مناسب دسترسی به جدول و viewهای مختلف انجام می‌دهید. تعداد کمی کاربر — اگر اصلاً — به جدول منبع دسترسی مستقیم دارند؛ کاربران به‌جای آن به یک یا چند view حق دسترسی می‌گیرند. گام اول این فرایند کپسوله‌سازی دسترسی به جدول اصلی با view است و سپس viewهای جدید را در صورت لزوم معرفی می‌کنید.

معاوضه‌های بالقوه (Potential Tradeoffs)

این بازآرایی — همان‌طور که در شکل ۹.۴ نشان داده شده — فقط وقتی کار می‌کند که پایگاه داده همان سطح دسترسی از طریق view را که به جداول دارد پشتیبانی کند. مثلاً اگر Customer توسط برنامهٔ بیرونی به‌روز می‌شود، پایگاه داده باید viewهای قابل‌به‌روزرسانی را پشتیبانی کند. اگر پشتیبانی نمی‌کند، بازآرایی Add CRUD Method (صفحهٔ ۲۳۲) را برای کپسوله‌سازی دسترسی به این جدول در نظر بگیرید.

شکل ۹.۴. کپسوله‌سازی جدول TCustomer با view.

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

همان‌طور که در شکل ۹.۴ می‌بینید، این بازآرایی ساده است. گام اول تغییر نام جدول موجود — در این مورد به TCustomer. گام دوم معرفی view با نام جدول اصلی — در این مورد Customer. از دید برنامه‌های بیرونی که به جدول دسترسی دارند، واقعاً چیزی تغییر نکرده است. آن‌ها فقط از طریق view به دادهٔ منبع دسترسی می‌یابند که برایشان مانند جدول اصلی به نظر می‌رسد.

یکی از راه‌های تغییر نام جدول Customer استفاده از بند RENAME TO دستور ALTER TABLE در SQL است، همان‌طور که در زیر نشان داده شده. اگر پایگاه داده این بند را پشتیبانی نمی‌کند، باید TCustomer ایجاد کنید، داده را از Customer کپی کنید و سپس جدول Customer را حذف کنید. نمونه‌ای از این رویکرد با بازآرایی Rename Table (صفحهٔ ۱۱۳) ارائه شده است. صرف‌نظر از نحوهٔ تغییر نام جدول، گام بعدی افزودن view با دستور CREATE VIEW است:

sql
ALTER TABLE Customer RENAME TO TCustomer;

CREATE VIEW Customer AS
  SELECT * FROM TCustomer;

مکانیک مهاجرت داده (Data-Migration Mechanics)

برای این بازآرایی پایگاه داده داده‌ای برای مهاجرت وجود ندارد.

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

نباید نیاز به به‌روزرسانی برنامه‌های دسترسی داشته باشید چون view از نظر ساختار با جدول اصلی یکسان است.

Introduce Calculation Method — معرفی متد محاسباتی

یک متد جدید — معمولاً stored function — که محاسبه‌ای با استفاده از دادهٔ ذخیره‌شده در پایگاه داده پیاده‌سازی می‌کند معرفی کنید.

شکل ۹.۵. معرفی متد محاسباتی برای Customer.

انگیزه (Motivation)

چند دلیل برای اعمال Introduce Calculation Method وجود دارد:

  • بهبود عملکرد برنامه. می‌توانید عملکرد کلی را با پیاده‌سازی محاسبه‌ای که به مقادیر زیادی داده نیاز دارد درون پایگاه داده و پاسخ دادن فقط با نتیجه بهبود دهید. این از ارسال دادهٔ لازم در شبکه برای انجام محاسبه جلوگیری می‌کند.
  • پیاده‌سازی محاسبهٔ مشترک و قابل‌استفادهٔ مجدد. یک محاسبه ممکن است توسط چند متد موجود پیاده‌سازی شده باشد. بنابراین منطقی است آن محاسبه را در یک متد پایگاه داده استخراج کنید که دیگران آن را فراخوانی کنند.
  • پشتیبانی از Introduce Calculated Column (صفحهٔ ۸۱). می‌توانید منطق لازم برای محاسبهٔ مقدار ستون را در stored function پیاده‌سازی کنید.
  • جایگزینی ستون محاسباتی. ممکن است بخواهید ستون محاسباتی را با stored procedureای که به‌جای آن فراخوانی می‌کنید جایگزین کنید. برای حذف ستون، بازآرایی Drop Column (صفحهٔ ۷۲) را اعمال کنید.

معاوضه‌های بالقوه (Potential Tradeoffs)

وقتی منطق زیادی درون پایگاه داده پیاده‌سازی می‌شود، اگر پایگاه داده برای تحمل بار معماری نشده باشد می‌تواند گلوگاه عملکرد شود. باید یا مطمئن شوید پایگاه داده مقیاس‌پذیر است یا میزان عملکردی که در آن پیاده‌سازی می‌کنید را محدود کنید.

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

برای به‌روزرسانی طرحوارهٔ پایگاه داده باید stored procedure را بنویسید و سپس تست کنید. اگر stored procedureهای موجود این منطق را پیاده‌سازی می‌کنند، باید بازآرایی شوند تا این stored procedure را فراخوانی کنند. کد زیر نحوهٔ معرفی stored function GetCustomerAccountTotal به پایگاه دادهٔ CustomerDB را نشان می‌دهد:

sql
CREATE OR REPLACE FUNCTION getCustomerAccountTotal
(CustomerID IN NUMBER) RETURN NUMBER IS
customerTotal NUMBER;
  BEGIN
     SELECT SUM(Amount) INTO customerTotal FROM Policy
       WHERE PolicyCustomerId=CustomerID;
         RETURN customerTotal;
       EXCEPTION WHEN no_data_found THEN
         RETURN 0;
  END;
END;
/

مکانیک مهاجرت داده (Data-Migration Mechanics)

برای این بازآرایی پایگاه داده داده‌ای برای مهاجرت وجود ندارد.

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

هنگام معرفی متد محاسباتی، باید همهٔ جاهایی در برنامه‌های بیرونی که این محاسبه فعلاً پیاده‌سازی شده را شناسایی کنید و سپس کد را برای فراخوانی stored procedure جدید بازآرایی کنید. کد زیر نشان می‌دهد محاسبه قبلاً به‌عنوان عملیات Java انجام می‌شد؛ اما بعداً عملیات فقط stored function مناسب را فراخوانی می‌کند:

java
//Before code
private BigDecimal getCustomerTotalBalance() {
BigDecimal customerTotalBalance = new BigDecimal(0);
for (Iterator iterator =
customer.getPolicies().iterator(); iterator.hasNext();)
{
  Policy policy = (Policy) iterator.next();
  customerTotalBalance.add(policy.getBalance());
}
return customerTotalBalance;
}

//After code
private BigDecimal getCustomerTotalBalance() {
  BigDecimal customerTotalBalance = new BigDecimal(0);
  stmt = connection.prepareCall("{call
  getCustomerAccountTotal(?)}");
  stmt.registerOutParameter(1, Types.NUMBER);
  stmt.setString(1, customer.getId);
  stmt.execute();
  customerTotalBalance = stmt.getBigDecimal(1);

    return customerTotalBalance;
}

ممکن است کشف کنید محاسبه در برنامه‌های مختلف به شکل‌های کمی متفاوت پیاده‌سازی شده — شاید قاعدهٔ کسب‌وکار در طول زمان تغییر کرده اما برنامه به‌روز نشده، یا شاید دلیل معتبری برای تفاوت‌ها وجود دارد. در هر صورت، باید هر تغییری را با ذی‌نفعان پروژهٔ مناسب هماهنگ کنید.

Introduce Index — معرفی ایندکس

یک ایندکس جدید از نوع یکتا (unique) یا غیریکتا (nonunique) معرفی کنید.

انگیزه (Motivation)

دلیل معرفی ایندکس به جدول افزایش عملکرد پرس‌وجو در خواندن‌های پایگاه داده است. همچنین ممکن است برای ایجاد کلید اصلی جدول یا پشتیبانی از کلید خارجی به جدول دیگر هنگام اعمال Consolidate Key Strategy (صفحهٔ ۱۶۸) نیاز به معرفی ایندکس داشته باشید.

معاوضه‌های بالقوه (Potential Tradeoffs)

ایندکس‌های زیاد روی یک جدول عملکرد را هنگام به‌روزرسانی، درج یا حذف از جدول کاهش می‌دهند. گاهی می‌خواهید ایندکس یکتا معرفی کنید اما نمی‌توانید چون دادهٔ موجود مقادیر تکراری دارد — مجبورید تکراری‌ها را قبل از اعمال این بازآرایی حذف کنید.

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

اعمال Introduce Index می‌تواند به‌دلیل وابستگی‌های داده پیچیده باشد و احتمالاً به‌روزرسانی هم داده و هم کد برنامه را لازم بدارد. باید موارد زیر را انجام دهید:

  1. نوع ایندکس را تعیین کنید. باید تصمیم بگیرید ایندکس یکتا یا غیریکتا نیاز دارید — معمولاً بر اساس قواعد کسب‌وکار پیرامون ویژگی‌های داده و نحوهٔ استفاده از داده تعیین می‌شود. مثلاً در ایالات متحده به افراد شمارهٔ تأمین اجتماعی یکتا (SSN) اختصاص می‌یابد. در بیشتر شرکت‌ها به مشتریان شمارهٔ مشتری یکتا اختصاص می‌یابد. اما شمارهٔ تلفن شما ممکن است یکتا نباشد (چند نفر ممکن است یک شماره را به اشتراک بگذارند). بنابراین SSN و CustomerNumber هر دو ستون‌های بالقوهٔ معتبر برای تعریف ایندکس یکتا هستند، اما TelephoneNumber احتمالاً ایندکس غیریکتا می‌خواهد.

  2. ایندکس جدید اضافه کنید. در مثال شکل ۹.۶، ایندکس جدیدی بر اساس SocialSecurityNumber برای Customer باید با دستور CREATE INDEX در SQL معرفی شود.

  3. فضای دیسک بیشتر فراهم کنید. هنگام استفاده از بازآرایی Introduce Index باید برای مصرف بیشتر فضای دیسک برنامه‌ریزی کنید؛ شاید نیاز به تخصیص فضای دیسک بیشتر داشته باشید.

شکل ۹.۶. معرفی ایندکس برای جدول Customer.

مکانیک مهاجرت داده (Data-Migration Mechanics)

به‌معنای دقیق داده‌ای برای مهاجرت وجود ندارد، اگرچه مقدار Customer.SocialSecurityNumber باید برای مقادیر تکراری بررسی شود اگر ایندکس یکتا معرفی می‌کنید. مقادیر تکراری باید با به‌روزرسانی آن‌ها یا تصمیم برای استفاده از ایندکس غیریکتا رسیدگی شوند. کد زیر تعیین می‌کند آیا مقادیر تکراری در ستون Customer.SocialSecurityNumber داریم:

sql
Find any duplicate values in customer.socialsecuritynumber.
SELECT SocialSecurityNumber,COUNT(SocialSecurityNumber)
  FROM Customer
  GROUP BY SocialSecurityNumber
  HAVING COUNT(SocialSecurityNumber)>1;

اگر مقادیر تکراری پیدا کردید، باید قبل از اعمال Introduce Index آن‌ها را تغییر دهید. کد زیر راهی برای این کار نشان می‌دهد: ابتدا از Customer.CustomerID به‌عنوان لنگر برای یافتن ردیف‌های تکراری استفاده می‌کنید و سپس مقادیر تکراری را با اعمال بازآرایی Update Data (صفحهٔ ۳۱۰) جایگزین می‌کنید:

sql
Create a temp table of the duplicates
CREATE TABLE temp_customer
AS
   SELECT * FROM Customer parent
   WHERE CustomerID != (SELECT MAX(CustomerID)
     FROM Customer child
     WHERE parent.SocialSecurityNumber =
     child.SocialSecurityNumber);
Now create the Unique Index
CREATE UNIQUE INDEX Customer_Name_UNQ
   ON Customer(SocialSecurityNumber)
;

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

برای به‌روزرسانی برنامه‌های دسترسی، ابتدا باید وابستگی‌ها را تحلیل کنید تا مشخص شود کدام برنامه‌های بیرونی به داده در Customer دسترسی دارند. اول، این برنامه‌های بیرونی باید بتوانند استثناهایی که پایگاه داده در صورت تولید مقادیر تکراری پرتاب می‌کند مدیریت کنند. دوم، باید پرس‌وجوهای خود را برای استفاده از این ایندکس جدید تغییر دهید تا عملکرد بازیابی داده بهتر شود. برخی محصولات پایگاه داده امکان مشخص کردن ایندکس مورد استفاده هنگام بازیابی ردیف‌ها از پایگاه داده را از طریق hint فراهم می‌کنند؛ نمونه‌ای در ادامه آمده:

sql
SELECT /*+ INDEX(Customer_Name_UNQ) */
CustomerID,
SocialSecurityNumber
FROM Customer
WHERE
  SocialSecurityNumber = 'XXX-XXX-XXX';

Introduce Read-Only Table — معرفی جدول فقط‌خواندنی

یک مخزن دادهٔ فقط‌خواندنی بر اساس جداول موجود در پایگاه داده ایجاد کنید. دو روش برای پیاده‌سازی این بازآرایی وجود دارد: جدولی که به‌صورت بلادرنگ پر می‌شود یا جدولی که به‌صورت دسته‌ای (batch) پر می‌شود.

انگیزه (Motivation)

چند دلیل برای اعمال Introduce Read-Only Table وجود دارد:

  • بهبود عملکرد پرس‌وجو. پرس‌وجوی مجموعه‌ای از جداول ممکن است به‌دلیل joinهای لازم بسیار کند باشد؛ بنابراین جدول ازپیش‌پرشده ممکن است عملکرد کلی را بهبود دهد.
  • خلاصه‌سازی داده برای گزارش‌گیری. بسیاری از گزارش‌ها به دادهٔ خلاصه نیاز دارند که می‌تواند در جدول فقط‌خواندنی ازپیش‌پر شود و بارها استفاده شود.
  • ایجاد دادهٔ افزون. بسیاری از برنامه‌ها داده را به‌صورت بلادرنگ از پایگاه‌های دادهٔ دیگر پرس‌وجو می‌کنند. جدول فقط‌خواندنی حاوی این داده در پایگاه دادهٔ محلی وابستگی شما به آن پایگاه(های) داده را کاهش می‌دهد و بافری برای زمانی که آن‌ها از کار می‌افتند یا برای نگهداری خارج از سرویس می‌شوند فراهم می‌کند.
  • جایگزینی خواندن‌های افزون. چند برنامهٔ بیرونی — یا stored procedure — اغلب همان پرس‌وجوی بازیابی را پیاده‌سازی می‌کنند. این پرس‌وجوها را می‌توان با جدول فقط‌خواندنی مشترک یا view جدید جایگزین کرد؛ Introduce View (صفحهٔ ۳۰۶) را ببینید.
  • امنیت داده. جدول فقط‌خواندنی به کاربران نهایی امکان پرس‌وجوی داده را می‌دهد اما نه به‌روزرسانی آن.
  • بهبود خوانایی پایگاه داده. اگر پایگاه دادهٔ بسیار نرمال‌شده دارید، معمولاً برای کاربران دشوار است در همهٔ جداول برای رسیدن به اطلاعات لازم حرکت کنند. با معرفی جداول فقط‌خواندنی که ساختارهای غیرنرمال‌شدهٔ رایج را ثبت می‌کنند، طرحوارهٔ پایگاه داده را آسان‌تر برای فهم می‌کنید چون مردم می‌توانند با تمرکز روی جداول غیرنرمال‌شده شروع کنند.

معاوضه‌های بالقوه (Potential Tradeoffs)

چالش اصلی با معرفی جدول فقط‌خواندنی «دادهٔ کهنه» است — داده‌ای که وضعیت فعلی منبعی که از آن پر شده را نمایش نمی‌دهد. مثلاً می‌توانید داده را از سیستم دور برای پر کردن جدول محلی بکشید و بلافاصله پس از آن دادهٔ منبع به‌روز شود. کاربران جدول فقط‌خواندنی باید هم به‌روز بودن دادهٔ کپی‌شده و هم نوسان دادهٔ منبع را درک کنند تا تعیین کنند آیا جدول فقط‌خواندنی برایشان قابل‌قبول است.

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

همان‌طور که در شکل ۹.۷ نشان داده شده، برای به‌روزرسانی طرحوارهٔ پایگاه داده هنگام انجام Introduce Read-Only Table، ابتدا باید جدول جدید را معرفی کنید. باید ساختار جدول فقط‌خواندنی که می‌خواهید معرفی کنید را تعیین کنید و سپس می‌توانید آن را با دستور CREATE TABLE ایجاد کنید. سپس راهبرد پر کردن (population strategy) را تعیین کنید. رویکرد بلادرنگ باید وقتی کاربران نهایی به اطلاعات به‌روز نیاز دارند اتخاذ شود؛ join برای ایجاد جدول فقط‌خواندنی نسبتاً ساده است و داده را می‌توان به‌ایمن به‌روز کرد؛ و جدول حاصل کوچک است و بنابراین عملکرد کافی را امکان‌پذیر می‌کند. رویکرد دسته‌ای باید وقتی رویکرد بلادرنگ مناسب نیست اتخاذ شود.

شکل ۹.۷. معرفی جدول فقط‌خواندنی CustomerPortfolio.

شکل ۹.۷ مثالی را نشان می‌دهد که جدول CustomerPortfolio جدول فقط‌خواندنی بر اساس جداول Customer، Account و Insurance است که کسب‌وکار انجام‌شده با هر مشتری را خلاصه می‌کند. این راه آسان‌تری برای کاربران نهایی برای پرس‌وجوهای ad-hoc که اطلاعات مشتری را تحلیل می‌کنند فراهم می‌کند. کد زیر DDL معرفی جدول CustomerPortfolio را نشان می‌دهد:

sql
CREATE TABLE CustomerPortfolio (
  CustomerID NUMBER NOT NULL,
  Name VARCHAR(40),
  PhoneNumber VARCHAR2(40),
  AccountsTotalBalance NUMBER,
  InsuranceTotalPayment NUMBER,
  InsuranceTotalValue NUMBER,
  CONSTRAINT PKCustomerPortfolio
     PRIMARY KEY (CustomerID)
  );

چند راهبرد پیاده‌سازی وجود دارد. اول، می‌توانید به توسعه‌دهندگان اعتماد کنید که کار درست را انجام دهند و فقط جدول را از طریق comment به‌عنوان فقط‌خواندنی علامت بزنید. دوم، می‌توانید triggerهایی پیاده‌سازی کنید که در درج، به‌روزرسانی یا حذف خطا پرتاب کنند. سوم، می‌توانید دسترسی به جدول را از طریق راهبرد SAC محدود کنید. چهارم، Encapsulate Table With View (صفحهٔ ۲۴۳) را اعمال کنید و view را فقط‌خواندنی کنید.

مکانیک مهاجرت داده (Data-Migration Mechanics)

باید ابتدا همهٔ دادهٔ منبع مربوط را به جدول فقط‌خواندنی کپی کنید و سپس راهبرد پر کردن (به‌روزرسانی بلادرنگ یا به‌روزرسانی دوره‌ای دسته‌ای) را اعمال کنید. چند راهبرد پیاده‌سازی برای راهبرد پر کردن وجود دارد:

  1. تازه‌سازی دوره‌ای. از job زمان‌بندی‌شده‌ای استفاده کنید که جدول فقط‌خواندنی را تازه می‌کند. job ممکن است همهٔ داده در جدول فقط‌خواندنی را تازه کند یا فقط تغییرات از آخرین تازه‌سازی را به‌روز کند. توجه کنید زمان تازه‌سازی داده باید کمتر از فاصلهٔ زمانی زمان‌بندی‌شدهٔ تازه‌سازی باشد. این تکنیک به‌ویژه برای محیط‌های شبیه انبار داده مناسب است، جایی که داده معمولاً خلاصه می‌شود و روز بعد استفاده می‌شود. بنابراین دادهٔ کهنه قابل‌تحمل است؛ همچنین این رویکرد راه آسان‌تری برای همگام‌سازی داده فراهم می‌کند.

  2. Materialized viewها. برخی محصولات پایگاه داده قابلیتی دارند که view دیگر فقط پرس‌وجو نیست؛ بلکه در واقع جدولی بر اساس پرس‌وجو است. پایگاه داده این materialized view را بر اساس گزینه‌هایی که هنگام ایجاد انتخاب می‌کنید به‌روز نگه می‌دارد. این تکنیک امکان استفاده از قابلیت‌های داخلی پایگاه داده برای تازه‌سازی داده در materialized view را می‌دهد؛ با معایب اصلی پیچیدگی SQL view. وقتی SQL view پیچیده‌تر می‌شود، محصولات پایگاه داده تمایل دارند همگام‌سازی خودکار view را پشتیبانی نکنند.

  3. همگام‌سازی مبتنی بر trigger. Trigger روی جداول منبع ایجاد کنید تا تغییرات دادهٔ منبع به جدول فقط‌خواندنی منتقل شود. این تکنیک امکان کدنویسی سفارشی همگام‌سازی داده را می‌دهد — مطلوب وقتی اشیای دادهٔ پیچیده باید همگام شوند؛ اما باید همهٔ triggerها را بنویسید که می‌تواند زمان‌بر باشد.

  4. به‌روزرسانی بلادرنگ برنامه. می‌توانید برنامه را تغییر دهید تا جدول فقط‌خواندنی را به‌روز کند و داده را جاری نگه دارد. این فقط وقتی کار می‌کند که همهٔ برنامه‌هایی که داده را به جداول منبع پایگاه داده می‌نویسند را بشناسید. این تکنیک به برنامه اجازه می‌دهد جدول فقط‌خواندنی را به‌روز کند و بنابراین همیشه جاری بماند، و می‌توانید مطمئن شوید داده توسط برنامه استفاده نمی‌شود. معایب این تکنیک این است که باید اطلاعات را دو بار بنویسید — اول به جدول اصلی و دوم به جدول غیرنرمال‌شدهٔ فقط‌خواندنی — که می‌تواند به تکرار و در نتیجه باگ منجر شود.

کد زیر نحوهٔ پر کردن داده در جدول CustomerPortfolio برای اولین بار را نشان می‌دهد:

sql
INSERT INTO CustomerPortfolio
  SELECT Customer.CustomerID,
    Customer.Name,
    Customer.PhoneNumber,
    SUM(Account.Balance),
    SUM(Insurance.Payment),
    SUM(Insurance.Value)
  FROM
    Customer,Account,Insurance
  WHERE
    Customer.CustomerID=Account.CustomerID
    AND Customer.CustomerID=Insurance.CustomerID
  GROUP BY
    Customer.CustomerID,
    Customer.Name,
    Customer.PhoneNumber;

کد زیر نحوهٔ همگام‌سازی داده از جداول منبع Customer، Account و Insurance را نشان می‌دهد. چون جداول منبع قابل‌به‌روزرسانی هستند اما CustomerPortfolio نیست، فقط به‌روزرسانی یک‌طرفه لازم است:

sql
CREATE OR REPLACE TRIGGER
UpdateCustomerPortfolioCustomer
  AFTER UPDATE OR INSERT OR DELETE
  ON Customer
  REFERENCING OLD AS OLD NEW AS NEW
  FOR EACH ROW
  DECLARE
  BEGIN
     IF DELETING THEN
       DeleteCustomerPortfolio;
    END IF;
     IF (UPDATING OR INSERTING) THEN
       UpdateCustomerPortfolio;
    END IF;
  END;
END;
/

CREATE OR REPLACE TRIGGER
UpdateCustomerPortfolioAccount
  AFTER UPDATE OR INSERT OR DELETE
  ON Account
  REFERENCING OLD AS OLD NEW AS NEW
  FOR EACH ROW
  DECLARE
  BEGIN
     UpdateCustomerPortfolioForAccount;
  END;
END;
/

CREATE OR REPLACE TRIGGER
UpdateCustomerPortfolioInsurance
  AFTER UPDATE OR INSERT OR DELETE
  ON Insurance
  REFERENCING OLD AS OLD NEW AS NEW
  FOR EACH ROW
  DECLARE
  BEGIN
     UpdateCustomerPortfolioForInsurance;
  END;
END;
/

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

قبلاً تحلیل کرده‌اید چرا این جدول فقط‌خواندنی را معرفی می‌کنید. مثلاً در شکل ۹.۷، اگر قرار است CustomerPortfolio را درون برنامه استفاده کنید، باید مطمئن شوید برنامه فقط برای اهداف فقط‌خواندنی از آن استفاده می‌کند. اگر CustomerPortfolio را به‌عنوان جدول خلاصه‌شده برای یکپارچه‌سازی با برنامهٔ دیگر ارائه می‌دهید، باید داده در CustomerPortfolio به‌روز نگه داشته شود. وقتی تصمیم می‌گیرید از دادهٔ CustomerPortfolio استفاده کنید، باید همهٔ جاهایی که فعلاً به جداول منبع دسترسی دارید را تغییر دهید و برای استفاده از CustomerPortfolio بازکار کنید.

همچنین ممکن است بخواهید به کاربران نهایی نشان دهید داده چقدر تازه است با نمایش مقدار ستون CustomerPortfolio.LastUpdatedTime. علاوه بر این، اگر گزارش‌های دسته‌ای به دادهٔ به‌روز نیاز دارند، job دسته‌ای باید بازکار شود تا ابتدا CustomerPortfolio را تازه کند و سپس گزارش‌ها را اجرا کند:

java
// Before code
stmt.prepare(
"SELECT Customer.CustomerId, " +
" Customer.Name, " +
" Customer.PhoneNumber, " +
" SUM(Account.Balance) AccountsTotalBalance, " +
" SUM(Insurance.Payment) InsuranceTotalPayment, " +
" SUM(Insurance.Value) InsuranceTotalPayment " +
"FROM Customer, Account, Insurance " +
"WHERE " +
" Customer.CustomerId = Account.CustomerId " +
" AND Customer.CustomerId = Insurance.CustomerId " +
" AND Customer.CustomerId = ?");
stmt.setLong(1,customer.getCustomerID);
stmt.execute();
ResultSet rs = stmt.executeQuery();

// After code
stmt.prepare(
"SELECT CustomerId, " +
" Name, " +
" PhoneNumber, " +
" AccountsTotalBalance, " +
" InsuranceTotalPayment, " +
" InsuranceTotalPayment " +
"FROM CustomerPortfolio " +
"WHERE CustomerId = ?");
stmt.setLong(1,customer.getCustomerID);
stmt.execute();
ResultSet rs = stmt.executeQuery();

Migrate Method From Database — انتقال متد از پایگاه داده

یک متد پایگاه دادهٔ موجود (stored procedure، stored function یا trigger) را در برنامه(های)ی که فعلاً آن را فراخوانی می‌کنند میزبانی مجدد کنید.

انگیزه (Motivation)

چهار دلیل برای اعمال Migrate Method From Database وجود دارد:

  • پشتیبانی از تنوع‌پذیری. وقتی متد در ابتدا در پایگاه داده پیاده‌سازی شد، منطق کسب‌وکار سازگار بود — یا حداقل فکر می‌شد سازگار باشد — بین برنامه‌ها. در طول زمان نیازمندی‌های برنامه تکامل یافت و اکنون منطق متفاوتی در برنامه‌های فردی لازم است.
  • افزایش قابلیت انتقال. زبان‌های متد پایگاه داده مختص فروشنده‌های پایگاه دادهٔ فردی هستند. با پیاده‌سازی منطق خارج از پایگاه داده — شاید در کامپوننت مشترک یا Web service — انتقال به پایگاه دادهٔ جدید آسان‌تر می‌شود.
  • افزایش مقیاس‌پذیری. اگرچه مقیاس‌پذیری پایگاه داده از طریق فناوری grid ممکن است، همچنان می‌توانید از راه‌های دیگر مانند افزودن سرورهای برنامهٔ بیشتر مقیاس دهید. راهبرد معماری سازمانی شما ممکن است مقیاس‌دهی سیستم‌ها از طریق روش‌های غیرپایگاه‌داده‌ای باشد؛ و اگر متد گلوگاه اثبات شود، می‌خواهید آن را از پایگاه داده خارج کنید.
  • افزایش قابلیت نگهداری. ابزارهای توسعه برای زبان‌های برنامه‌نویسی پیشرو مانند Java، C# و Visual Basic اغلب بسیار پیشرفته‌تر از ابزارهای زبان‌های برنامه‌نویسی پایگاه داده هستند. ابزارهای بهتر — و البته شیوه‌های توسعهٔ بهتر — کد را آسان‌تر و در نتیجه ارزان‌تر برای نگهداری می‌کنند. همچنین با برنامه‌نویسی در یک زبان، نیازمندی‌های مهارت برنامه‌نویسی اعضای تیم را کاهش می‌دهید — یافتن کسی با تجربهٔ C# آسان‌تر از یافتن کسی با تجربهٔ C# و Oracle PL/SQL است.

معاوضه‌های بالقوه (Potential Tradeoffs)

چند معاوضه با این بازآرایی همراه است:

  • کاهش قابلیت استفادهٔ مجدد. پایگاه‌های دادهٔ رابطه‌ای فناوری کمترین مخرج مشترک هستند. تقریباً هر فناوری برنامه‌ای می‌تواند به آن‌ها دسترسی داشته باشد و بنابراین پیاده‌سازی منطق مشترک درون پایگاه دادهٔ رابطه‌ای بیشترین شانس برای قابلیت استفادهٔ مجدد را دارد.
  • کاهش عملکرد. احتمال کاهش عملکرد وجود دارد، به‌ویژه اگر متد به مقادیر زیادی داده دسترسی داشته باشد که باید قبل از پردازش به متد منتقل شود.

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

همان‌طور که در شکل ۹.۸ نشان داده شده، تغییر در طرحوارهٔ پایگاه داده ساده است — فقط متد را برای حذف علامت می‌زنید و پس از پایان دورهٔ گذار، متد را فیزیکی از پایگاه داده حذف می‌کنید. در این مثال، stored procedure GetValidPolicies از CustomerDB به برنامهٔ مدیریت بیمه‌نامه‌ها منتقل شد. این کار به چند دلیل انجام شد: فقط یک برنامه به آن منطق کسب‌وکار نیاز داشت، ترافیک شبکه صرف‌نظر از محل انجام عملکرد یکسان ماند، و تیم پروژه می‌خواست قابلیت نگهداری برنامه را بهبود دهد. جالب است که نام متد کمی تغییر کرد تا قراردادهای نام‌گذاری زبان برنامه‌نویسی را منعکس کند.

شکل ۹.۸. انتقال کد بازیابی بیمه‌نامه به برنامهٔ مدیریت بیمه‌نامه.

مکانیک مهاجرت داده (Data-Migration Mechanics)

برای این بازآرایی پایگاه داده داده‌ای برای مهاجرت وجود ندارد.

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

متد باید در برنامه(های) مناسب توسعه و تست شود. باید کد برنامه را برای فراخوانی‌های متد موجود جستجو کنید و سپس آن کد را با فراخوانی تابع متناظر جایگزین کنید. مثال کد زیر نشان می‌دهد کد برنامه چگونه برای جایگزینی عملکردی که متد فراهم می‌کرد توسعه می‌یابد:

java
//Before code
stmt.prepareCall("begin ? := getValidPolicies(); end;");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
stmt.execute();
ResultSet rs = stmt.getObject(1);
List validPolicies = new ArrayList();
Policy policy = new Policy();
while (rs.next()) {
  policy.setPolicyId(rs.getLong(1));
  policy.setCustomerID(rs.getLong(2));
  policy.setActivationDate(rs.getDate(3));
  policy.setExpirationDate(rs.getDate(4));
  validPolicies.add(policy);
}
return validPolicies;

//After code
stmt.prepare(
  "SELECT PolicyId, CustomerId, "+
  "ActivationDate, ExpirationDate " +
  "FROM Policy" +
  "WHERE ActivationDate < TRUNC(SYSDATE) AND "+
  "ExpirationDate IS NOT NULL AND "+
  "ExpirationDate > TRUNC(SYSDATE)");
ResultSet rs = stmt.execute();
List validPolicies = new ArrayList();
Policy policy = new Policy();
while (rs.next()) {
  policy.setPolicyId(rs.getLong("PolicyId"));
  policy.setCustomerID(rs.getLong("CustomerId"));
  policy.setActivationDate(rs.getDate
  ("ActivationDate"));
  policy.setExpirationDate(rs.getDate
  ("ExpirationDate"));
  validPolicies.add(policy);
}
return validPolicies;

Migrate Method To Database — انتقال متد به پایگاه داده

منطق موجود برنامه را در پایگاه داده میزبانی مجدد کنید.

انگیزه (Motivation)

سه دلیل برای اعمال Migrate Method To Database وجود دارد:

  • پشتیبانی از استفادهٔ مجدد. تقریباً هر فناوری برنامه‌ای می‌تواند به پایگاه‌های دادهٔ رابطه‌ای دسترسی داشته باشد و بنابراین پیاده‌سازی منطق مشترک به‌عنوان متدهای پایگاه داده (stored procedure، function یا trigger) درون پایگاه دادهٔ رابطه‌ای بیشترین شانس برای قابلیت استفادهٔ مجدد را دارد.
  • افزایش مقیاس‌پذیری. مقیاس‌پذیری پایگاه داده از طریق فناوری grid ممکن است؛ بنابراین معماری سازمانی شما ممکن است شما را به میزبانی همهٔ منطق داده‌محور درون پایگاه داده هدایت کند.
  • بهبود عملکرد. احتمال بهبود عملکرد وجود دارد، به‌ویژه اگر stored procedure مقادیر زیادی داده را پردازش کند، چون پردازش نزدیک‌تر به پایگاه داده انجام می‌شود که منجر به مجموعهٔ نتیجهٔ کوچک‌تری در شبکه می‌شود.

معاوضه‌های بالقوه (Potential Tradeoffs)

عیب اصلی این بازآرایی کاهش قابلیت انتقال متدهای پایگاه داده است — کدی که مختص فروشندهٔ پایگاه دادهٔ فردی است. این مشکل اغلب توسط پوریست‌ها بزرگ‌نمایی می‌شود — برای سازمان‌ها رایج نیست فروشندهٔ پایگاه داده را عوض کنند، شاید چون فروشندگان پایگاه مشتریان موجود را قفل کرده‌اند یا شاید چون دیگر هزینه‌اش نمی‌ارزد.

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

همان‌طور که در شکل ۹.۹ نشان داده شده، تغییر در طرحوارهٔ پایگاه داده ساده است — فقط stored procedure را توسعه و تست می‌کنید. در این مثال، منطق شناسایی فهرست مشتریان معوق — کسانی که در پرداخت‌ها عقب‌اند — است. این منطق در دو جا پیاده‌سازی شده: برنامه‌های Policy Administration و Customer Credit. هر برنامه عملیات را متفاوت نام‌گذاری کرده — به‌ترتیب IdentifyDefaultedCustomers() و ListCustomersThatDefaulted() — اگرچه هر دو با CustomerDB.GetDefaultedCustomers() جایگزین می‌شوند.

شکل ۹.۹. انتقال منطق برنامه به پایگاه داده.

مکانیک مهاجرت داده (Data-Migration Mechanics)

برای این بازآرایی پایگاه داده داده‌ای برای مهاجرت وجود ندارد.

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

منطق متد باید از هر برنامه‌ای که آن را پیاده‌سازی می‌کند حذف شود و به‌جای آن stored procedure فراخوانی شود. ساده‌ترین راه این است که stored procedure را از متد(های) موجود برنامه فراخوانی کنید. احتمالاً کشف می‌کنید برنامه‌های فردی این متد را متفاوت نام‌گذاری کرده‌اند، یا حتی متفاوت طراحی کرده‌اند. مثلاً یک برنامه ممکن است منطق کسب‌وکار را به‌عنوان یک تابع بزرگ پیاده‌سازی کند، در حالی که دیگری آن را به چند تابع کوچک‌تر.

به‌طور مشابه، ممکن است کشف کنید برنامه‌های مختلف متد را به روش‌های متفاوت پیاده‌سازی می‌کنند — یا چون کد دیگر نیازمندی‌های واقعی را منعکس نمی‌کند (اگر اصلاً منعکس کرده بود) یا چون برنامه‌های فردی دلیل خوبی برای پیاده‌سازی متفاوت منطق داشتند. مثلاً عملیات DetermineVacationDays(Year) فهرستی از تاریخ‌هایی که کارمندان مرخصی با حقوق می‌گیرند فراهم می‌کند. این عملیات در چند برنامه پیاده‌سازی شده، اما با بررسی کد، به روش‌های متفاوت پیاده‌سازی شده است. نسخه‌های مختلف در زمان‌های مختلف نوشته شده‌اند، قواعد از زمان نوشتن برخی نسخه‌های قدیمی‌تر تغییر کرده‌اند، و قواعد بر اساس کشور، ایالت و گاهی حتی شهر متفاوت است. در این نقطه باید یا تصمیم بگیرید نسخه‌های مختلف را رها کنید (مثلاً با تفاوت‌ها زندگی کنید)، متدهای موجود برنامه را اصلاح کنید، یا stored procedure(هایی) در پایگاه داده بنویسید که نسخهٔ صحیح منطق را پیاده‌سازی کند.

نمونهٔ کد زیر نشان می‌دهد منطق برنامه چگونه به پایگاه داده منتقل شد و برنامه اکنون چگونه از stored procedure برای دریافت فهرست مشتریان معوق استفاده می‌کند. مثال کد ایجاد stored procedure را نشان نمی‌دهد:

java
//Before code
stmt.prepare(
  "SELECT CustomerId, " +
  "PaymentAmount" +
  "FROM Transactions" +
  "WHERE LastPaymentdate < TRUNC(SYSDATE-90) AND " +
  "PaymentAmount >30 ");
ResultSet rs = stmt.execute();
List defaulters = new ArrayList();
DefaultedCustomer defaulted = new DefaultedCustomer();
while (rs.next()) {
  defaulted.setCustomerID(rs.getLong("CustomerId"));
  defaulted.setAmount(rs.getBigDecimal
  ("PaymentAmount"));
  defaulters.add(defaulted);
}
return defaulters;

//After code
stmt.prepareCall("begin ? := getDefaultedCustomers(); end;");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
stmt.execute();
ResultSet rs = stmt.getObject(1);
List defaulters = new ArrayList();
DefaultedCustomer defaulted = new DefaultedCustomer();
while (rs.next()) {
  defaulted.setCustomerID(rs.getLong(1));
  defaulted.setAmount(rs.getBigDecimal(2));
  defaulters.add(defaulted);
}
return defaulters;

Replace Method(s) With View — جایگزینی متد(ها) با نما

یک view بر اساس یک یا چند متد پایگاه دادهٔ موجود (stored procedure، stored function یا trigger) درون پایگاه داده ایجاد کنید.

انگیزه (Motivation)

سه دلیل اساسی برای اعمال Replace Method(s) With View وجود دارد:

  • سهولت استفاده. ممکن است ابزارهای جدیدی — به‌ویژه ابزارهای گزارش‌گیری — پذیرفته باشید که با view بسیار آسان‌تر از متدها کار می‌کنند.
  • کاهش نگهداری. بسیاری از مردم تعاریف view را آسان‌تر از متدها برای نگهداری می‌یابند.
  • افزایش قابلیت انتقال. می‌توانید قابلیت انتقال طرحوارهٔ پایگاه داده را افزایش دهید. زبان‌های متد پایگاه داده مختص فروشنده‌های پایگاه دادهٔ فردی هستند، در حالی که تعاریف view را می‌توان طوری نوشت که با استانداردهای SQL سازگار باشند.

معاوضه‌های بالقوه (Potential Tradeoffs)

این بازآرایی معمولاً فقط روی متدهای نسبتاً ساده‌ای که منطقی را پیاده‌سازی می‌کنند و می‌توان آن را با تعریف view هم پیاده‌سازی کرد قابل اعمال است. پیامد این است که این بازآرایی انعطاف معماری شما را محدود می‌کند. علاوه بر این، اگر پایگاه داده viewهای قابل‌به‌روزرسانی را پشتیبانی نمی‌کند، فقط به جایگزینی متدهای مرتبط با بازیابی محدود هستید. عملکرد و مقیاس‌پذیری به‌ندرت تحت تأثیر قرار می‌گیرند چون همهٔ کار همچنان درون پایگاه داده انجام می‌شود.

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

برای به‌روزرسانی طرحوارهٔ پایگاه داده، ابتدا باید view را از طریق بازآرایی Introduce View (صفحهٔ ۳۰۶) معرفی کنید. سپس باید متد را برای حذف علامت بزنید و پس از انقضای دورهٔ گذار با دستور DROP PROCEDURE آن را حذف کنید. شکل ۹.۱۰ مثالی را نشان می‌دهد که stored procedure GetCustomerAccountList با view CustomerAccountList جایگزین می‌شود. کد زیر DDL انجام این کار را نشان می‌دهد:

sql
CREATE VIEW CustomerAccountList (
  CustomerID      NUMBER NOT NULL,
  CustomerName    VARCHAR(40),
  CustomerPhone VARCHAR2(40),
  AccountNumber VARCHAR(14),
  AccountBalance NUMBER,
) AS
SELECT
  Customer.CustomerID,
  Customer.Name,
  Customer.PhoneNumber,
  Account.AccountNumber,
  Account.Balance
FROM Customer,Account
WHERE Customer.CustomerID=Account.CustomerID
;

 Run this code after June 14 2007
DROP PROCEDURE GetCustomerAccountList

شکل ۹.۱۰. معرفی view CustomerAccountList.

مکانیک مهاجرت داده (Data-Migration Mechanics)

برای این بازآرایی پایگاه داده داده‌ای برای مهاجرت وجود ندارد.

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

باید برنامه‌های دسترسی را برای کار از طریق view به‌جای فراخوانی stored procedure بازآرایی کنید. کدهای خطای پرتاب‌شده توسط پایگاه داده هنگام استفاده از view تغییر می‌کنند، بنابراین ممکن است نیاز به بازکار کد مدیریت خطا داشته باشید. کد زیر نشان می‌دهد چگونه برنامه برای فراخوانی view به‌جای stored procedure تغییر می‌کند:

java
//Before code
stmt.prepareCall("begin ? := getCustomerAccountList(?); end;");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
stmt.setInt(1,customerId);
stmt.execute();
ResultSet rs = stmt.getObject(1);
List customerAccounts = new ArrayList();
while (rs.next()) {
  customerAccounts.add(populateAccount(rs));
}
return customerAccounts;

//After code

stmt.prepare(
  "SELECT CustomerID, CustomerName, "+
  "CustomerPhone, AccountNumber, AccountBalance " +
  "FROM CustomerAccountList " +
  "WHERE CustomerId = ? ");
stmt.setLong(1,customerId);
ResultSet rs = stmt.executeQuery();
List customerAccounts = new ArrayList();
while (rs.next()) {
  customerAccounts.add(populateAccount(rs));
}
return customerAccounts;

Replace View With Method(s) — جایگزینی نما با متد(ها)

یک view موجود را با یک یا چند متد موجود (stored procedure، stored function یا trigger) درون پایگاه داده جایگزین کنید.

انگیزه (Motivation)

دو دلیل اساسی برای اعمال Replace View With Method(s) وجود دارد. اول، با متدها می‌توان منطق پیچیده‌تری نسبت به view پیاده‌سازی کرد؛ بنابراین این بازآرایی گام اول در آن جهت خواهد بود. دوم، متدها می‌توانند جداول داده را به‌روز کنند. برخی پایگاه‌های داده viewهای قابل‌به‌روزرسانی را پشتیبانی نمی‌کنند، یا اگر پشتیبانی کنند، اغلب به یک جدول محدود است. با حرکت از راهبرد کپسوله‌سازی مبتنی بر view به مبتنی بر متد، معماری پایگاه داده انعطاف‌پذیرتر می‌شود.

معاوضه‌های بالقوه (Potential Tradeoffs)

چند مشکل بالقوه با این بازآرایی وجود دارد. اول، ابزارهای گزارش‌گیری معمولاً با متدها خوب کار نمی‌کنند، اما با view کار می‌کنند. دوم، احتمال کاهش قابلیت انتقال وجود دارد چون زبان‌های متد پایگاه داده مختص فروشنده‌های پایگاه دادهٔ فردی هستند. سوم، قابلیت نگهداری ممکن است کاهش یابد چون بسیاری ترجیح می‌دهند با view به‌جای متد (و بالعکس) کار کنند. خوشبختانه عملکرد و مقیاس‌پذیری به‌ندرت تحت تأثیر قرار می‌گیرند چون همهٔ کار همچنان درون پایگاه داده انجام می‌شود.

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

برای به‌روزرسانی طرحوارهٔ پایگاه داده، ابتدا باید متد(های) مناسب لازم برای جایگزینی view را معرفی کنید. سپس باید view را برای حذف علامت بزنید و پس از انقضای دورهٔ گذار با بازآرایی Drop View (صفحهٔ ۷۹) آن را حذف کنید.

شکل ۹.۱۱ مثالی را نشان می‌دهد که view CustomerTransactionsHistory با stored procedure GetCustomerTransactions جایگزین می‌شود. کد زیر کد معرفی متد و حذف view را نشان می‌دهد:

sql
CREATE OR REPLACE PROCEDURE GetCustomerTransactions
{
   P_CustomerID IN NUMBER
   P_Start IN DATE
   P_End IN DATE
}
IS
BEGIN
   SELECT *
   FROM Transaction
   WHERE Transaction.CustomerID = P_CustomerID
   AND Transaction.PostingDate BETWEEN P_Start AND P_End;
END;

On March 14 2007
DROP VIEW CustomerTransactionsHistory;

شکل ۹.۱۱. معرفی stored procedure GetCustomerTransactions.

مکانیک مهاجرت داده (Data-Migration Mechanics)

برای این بازآرایی پایگاه داده داده‌ای برای مهاجرت وجود ندارد.

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

باید برنامه‌های دسترسی را برای کار از طریق متد(ها) به‌جای view بازآرایی کنید. کدهای خطای پرتاب‌شده توسط پایگاه داده هنگام استفاده از متدها تغییر می‌کنند، بنابراین ممکن است نیاز به بازکار کد مدیریت خطا داشته باشید.

وقتی view CustomerTransactionsHistory را با stored procedure GetCustomerTransactions جایگزین می‌کنید، کد شما باید همان‌طور که در زیر نشان داده شده تغییر کند:

java
//Before code
stmt.prepare(
  "SELECT * " +
  "FROM CustomerTransactionsHistory " +
  "WHERE CustomerId = ? "+
  "AND TransactionDate BETWEEN ? AND ? ");
stmt.setLong(1,customerId);
stmt.setDate(2,startDate);
stmt.setDate(3,endDate);
ResultSet rs = stmt.executeQuery();
List customerTransactions = new ArrayList();
while (rs.next()) {
  customerTransactions.add(populateTransactions(rs));
}
return customerTransactions;

//After code
stmt.prepareCall("begin ? :=

getCustomerTransactions(?,?,?); end;");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
stmt.setInt(1,customerId);
stmt.setDate(2,startDate);
stmt.setDate(3,endDate);
stmt.execute();
ResultSet rs = stmt.getObject(1);
List customerTransactions = new ArrayList();
while(rs.next()) {
  customerTransactions.add(populateAccount(rs));
}
return customerTransactions;

Use Official Data Source — استفاده از منبع دادهٔ رسمی

از منبع دادهٔ رسمی برای یک موجودیت مشخص استفاده کنید، به‌جای منبعی که فعلاً استفاده می‌کنید.

انگیزه (Motivation)

دلیل اصلی اعمال Use Official Data Source استفاده از نسخهٔ صحیح داده برای جدول یا جداول مشخص است. وقتی همان داده در چند مکان ذخیره می‌شود، خطر ناسازگاری و فقدان دسترس‌پذیری را دارید. مثلاً فرض کنید چند پایگاه داده در سازمان دارید که یکی از آن‌ها — پایگاه دادهٔ CRM — منبع رسمی اطلاعات مشتری است.

اگر برنامه شما از جدول Customer خودش استفاده می‌کند، ممکن است با همهٔ دادهٔ مشتری موجود در سازمان کار نکنید. بدتر از آن، برنامه شما می‌تواند مشتری جدیدی ثبت کند اما اطلاعاتشان به پایگاه دادهٔ CRM در دسترس قرار نمی‌گیرد و بنابراین برای سایر برنامه‌های سازمان در دسترس نیست.

معاوضه‌های بالقوه (Potential Tradeoffs)

معاوضهٔ اصلی هزینهٔ بازآرایی همهٔ ارجاعات به جدول در پایگاه دادهٔ محلی برای استفاده از جداول پایگاه دادهٔ رسمی است. اگر راهبرد کلید منبع دادهٔ رسمی با آنچه جدول شما استفاده می‌کند متفاوت است، ممکن است ابتدا بخواهید Consolidate Key Strategy (صفحهٔ ۱۶۸) را اعمال کنید تا شناسه‌های استفاده‌شده در پایگاه دادهٔ شما منعکس‌کنندهٔ منبع دادهٔ رسمی باشند. علاوه بر این، معناشناسی و به‌موقع بودن دادهٔ منبع رسمی ممکن است با داده‌ای که فعلاً استفاده می‌کنید یکسان نباشد. ممکن است نیاز به اعمال بازآرایی‌هایی مانند Apply Standard Codes (صفحهٔ ۱۵۷)، Apply Standard Type (صفحهٔ ۱۶۲) و Introduce Common Format (صفحهٔ ۱۸۳) داشته باشید تا دادهٔ موجود را به چیزی که با منبع دادهٔ رسمی سازگار است تبدیل کنید.

مکانیک به‌روزرسانی طرحواره (Schema Update Mechanics)

برای به‌روزرسانی طرحواره باید موارد زیر را انجام دهید:

  1. منبع دادهٔ رسمی را شناسایی کنید. باید منبع دادهٔ رسمی را شناسایی کنید که اغلب در پایگاه دادهٔ خارجی خارج از کنترل شما خواهد بود. بدتر از آن، ممکن است چند «منبع رسمی» وجود داشته باشد که باید از بین آن‌ها انتخاب کنید یا برای موقعیت خود به‌طور مناسب ادغام کنید. باید با ذی‌نفع(های) پروژه و مالکان منبع داده توافق کنید که برنامهٔ شما باید به آن دسترسی داشته باشد.

  2. راهبرد پیاده‌سازی را انتخاب کنید. دو انتخاب دارید: یا برنامه(های) خود را بازکار کنید تا مستقیماً به منبع دادهٔ رسمی دسترسی داشته باشند (راهبرد نشان‌داده‌شده در شکل ۹.۱۲) یا دادهٔ منبع را با جدول موجود تکرار کنید (راهبرد نشان‌داده‌شده در شکل ۹.۱۳). وقتی منبع دادهٔ رسمی در پایگاه دادهٔ دیگر است، راهبرد replication بهتر از راهبرد دسترسی مستقیم مقیاس می‌گیرد چون برنامهٔ شما احتمالاً فقط به یک پایگاه داده وابسته می‌شود.

  3. راهبرد دسترسی مستقیم. برنامه را طوری تغییر می‌دهید که اکنون مستقیماً به CustomerDatabase دسترسی داشته باشد. توجه کنید این ممکن است به اتصال پایگاه دادهٔ متفاوتی از آنچه فعلاً استفاده می‌شود نیاز داشته باشد، یا فراخوانی web service یا تراکنش. با دنبال کردن این راهبرد، باید بتوانید تراکنش‌ها را در پایگاه‌های دادهٔ مختلف مدیریت کنید.

  4. راهبرد replication. می‌توانید replication بین YourDatabase و CustomerDatabase تنظیم کنید تا همهٔ جداول موردنیاز را تکرار کنید. اگر می‌خواهید جداول قابل‌به‌روزرسانی در YourDatabase داشته باشید، باید از multimaster replication استفاده کنید. با دنبال کردن این راهبرد، نباید نیاز به تغییر کد برنامه داشته باشید تا وقتی طرحواره و معناشناسی دادهٔ منبع یکسان بماند. اگر تغییراتی در طرحواره لازم باشد — مانند تغییر نام جداول — یا بدتر از آن، معناشناسی دادهٔ رسمی با دادهٔ فعلی متفاوت باشد، احتمالاً به تغییر در برنامه‌های بیرونی نیاز دارید.

  5. جداولی که دیگر استفاده نمی‌شوند را حذف کنید. وقتی دسترسی مستقیم به دادهٔ منبع رسمی را انتخاب می‌کنید، دیگر به جداول در YourDatabase نیازی ندارید. باید از بازآرایی Drop Table (صفحهٔ ۷۷) برای حذف آن جداول استفاده کنید.

شکل ۹.۱۲. دسترسی مستقیم به دادهٔ رسمی مشتری از پایگاه دادهٔ Customer.

شکل ۹.۱۳. استفاده از دادهٔ رسمی مشتری از طریق راهبرد replication.

مکانیک مهاجرت داده (Data-Migration Mechanics)

برای این بازآرایی پایگاه داده داده‌ای برای مهاجرت وجود ندارد اگر معناشناسی دادهٔ YourDatabase رسمی و YourDatabase محلی یکسان باشد. اگر یکسان نباشند، باید یا از این بازآرایی صرف‌نظر کنید، راهبرد replication را دنبال کنید که در آن مقادیر متفاوت را رفت‌وبرگشت تبدیل می‌کنید، یا برنامه(های) خود را بازآرایی کنید تا معناشناسی دادهٔ منبع رسمی را بپذیرند. مگر اینکه داده از نظر معناشناسی مشابه باشد، یا خوش‌شانس باشید و راهی امن برای تبدیل داده رفت‌وبرگشت پیدا کنید، بعید است راهبرد replication برای شما کار کند.

مکانیک به‌روزرسانی برنامهٔ دسترسی (Access Program Update Mechanics)

نحوهٔ تغییر برنامه‌های بیرونی بسته به راهبرد پیاده‌سازی متفاوت است. اگر از راهبرد دسترسی مستقیم استفاده می‌کنید، برنامه‌ها باید اکنون به منبع دادهٔ رسمی CustomerDatabase متصل شوند و با آن کار کنند. با راهبرد replication، باید اسکریپت‌های replication بین جداول مناسب در YourDatabase و CustomerDatabase ایجاد کنید. وقتی جدول(های) در YourDatabase با جدول(های) در CustomerDatabase مطابقت دارند، برنامه‌ها نباید نیاز به تغییر داشته باشند. در غیر این صورت، یا باید طرحواره و معناشناسی منبع دادهٔ رسمی را بپذیرید و سپس برنامه(های) خود را بازآرایی کنید، یا باید راهی برای پیاده‌سازی replication پیدا کنید که طرحواره در YourDatabase تغییر نکند. یکی از راه‌ها پیاده‌سازی اسکریپت‌هایی است که داده را رفت‌وبرگشت تبدیل می‌کنند — که اغلب در عمل دشوار است چون نگاشت‌ها به‌ندرت یک‌به‌یک هستند. راه دیگر، به‌همان اندازه دشوار، جایگزینی جدول(های) منبع در YourDatabase با جدول(های) مناسب از CustomerDatabase و سپس اعمال بازآرایی Encapsulate Table With View (صفحهٔ ۲۴۳) است تا برنامه‌های موجود همچنان با «طرحوارهٔ قدیمی» کار کنند. این view(های) جدید باید همان منطق تبدیل اسکریپت‌های ذکرشده را پیاده‌سازی کنند.

کد زیر نشان می‌دهد چگونه برنامه را برای کار با منبع دادهٔ رسمی با استفاده از اتصال crmDB به‌جای DB تغییر دهید:

java
// Before code
stmt = DB.prepare("select CustomerID,Name,PhoneNumber "+
  "FROM Customer WHERE CustomerID = ?");
stmt.setLong(1, customerID);
stmt.execute();
ResultSet rs = stmt.executeQuery();

// After code
stmt = crmDB.prepare("select CustomerID,Name,PhoneNumber "+
  "FROM Customer WHERE CustomerID = ?");
stmt.setLong(1, customerID);
stmt.execute();
ResultSet rs = stmt.executeQuery();