აქ არის ხარვეზი, რომელიც ორჯერ ვნახე, ორ სხვადასხვა ძრავში. ექსპორტი 10:00-ზე მუშაობს და იმახსოვრებს უმაღლეს ბოლო ცვლილების დროის ნიშანს, რომელიც ნახა. ერთი ტრანზაქცია, რომელიც 09:58-ზე დაიწყო, ჯერ კიდევ ღიაა, commit-დება 10:03-ზე და თან ატარებს დროის ნიშანს თავისი დაწყების მომენტიდან. შემდეგი ექსპორტი მხოლოდ 10:00-ზე ახალ სტრიქონებს ითხოვს და ვერასოდეს ხედავს მას. გადაცემის მოცულობა შესანიშნავი იყო, მონაცემები კი არასწორი.

მიჰყევით ექსპორტს, რომელმაც სტრიქონი დაკარგა

მიჰყევით მოვლენების რიგს და არა SQL-ს. აპლიკაცია სტრიქონის ცვლილების დროს ტრანზაქციის დაწყებისას წერს, არა commit-ისას. ექსპორტიორი კითხულობს კედლის საათის წყლის ნიშანს, სანამ ტრანზაქცია ჯერ კიდევ ღიაა. შემდეგ ტრანზაქცია commit-დება შენახულ წყლის ნიშანზე უფრო ძველი ცვლილების დროით. მომხმარებლის შემდეგი პარტია წყლის ნიშნის შემდეგ იწყება, ამიტომ სტრიქონი კურსორის უკან რჩება და აღარასოდეს შეირჩევა.

არაფერი არ ლოგავს შეცდომას, რადგან არაფერი არ ჩავარდა. სწორედ ეს ხდის ამ კლასის ხარვეზს ძვირად: დელტა ნაკადი სწრაფია, სტრიქონების რაოდენობა დამაჯერებლად გამოიყურება და დაკარგული სტრიქონი კვირების შემდეგ ჩნდება შეჯერების ბილეთად, რომელსაც ვერავინ ვერ იმეორებს.

მიმდევრობის ნომრებს იგივე ფორმის ნაკლი აქვს სხვა მიზეზით. მონოტონური ID გეუბნებათ მნიშვნელობების განაწილების რიგს, და არა ტრანზაქციების commit-ის რიგს. დაბალი ნომრის ტრანზაქცია შეიძლება commit-დეს მაღალი ნომრის შემდეგ, ამიტომ განაწილების რიგზე დაფუძნებულ კურსორსაც შეუძლია ხვრელი დატოვოს.

ხუთი დაპირება, რომელიც ნაკადმა უნდა შეასრულოს

ტრანსპორტის არჩევამდე სთხოვეთ წყარო სისტემას ხუთპუნქტიანი ხელშეკრულება. თუ რომელიმე პუნქტი აკლია, თქვენ გაქვთ ევრისტიკა და არა ცვლილებების ნაკადი.

  • დაფარვა: ჩასმები, განახლებები და წაშლები, თითოეული გამოყენებისთვის საჭირო სტაბილური კლავიშით.
  • საზღვარი: რას ნიშნავს კურსორის მნიშვნელობა და რას შეიცავს თანმიმდევრული პარტია.
  • თანმიმდევრულობა: როგორ იკითხება დაკავშირებული ცხრილები შეუთავსებელი წყაროს მდგომარეობების შერევის გარეშე.
  • შენახვა: რამდენ ხანს შეუძლია გათიშულ მომხმარებელს განაგრძოს შენახული პოზიციიდან.
  • ხელახალი ინიციალიზაცია: მხარდაჭერილი სრული snapshot, როცა ეს პოზიცია აღარ არის ძალაში.

მხარდაჭერილ მექანიზმს შეუძლია ხუთივე დააკმაყოფილოს. SQL Server-ის ცვლილებების თვალყურის დევნების დოკუმენტაცია ერთი კონკრეტული გამოქვეყნებული მაგალითია: ის განსაზღვრავს მინიმალურ ძალაში მყოფ ვერსიას, აღრიცხავს წაშლებსაც და ცვლილებებსაც, და აღწერს snapshot ტრანზაქციას, რომელიც მოიცავს ვალიდაციას, ვერსიის აღებას და დაკავშირებულ ცვლილების მოთხოვნებს. ეს არის მაგალითი იმისა, რა უნდა მოითხოვოთ წყაროსგან, და არა სინტაქსი, რომელიც სხვა ძრავში ჩასვამთ.

დააპროექტეთ საკონტროლო წერტილი მილსადენის ნაწილად

მომხმარებლის შენახული პოზიცია ნამდვილი მდგომარეობის მანქანაა, ამიტომ ისე ჩაწერეთ. კურსორს წინ გადაადგილება მხოლოდ იმ სამუშაო ნაკადით შეუძლია, რომელმაც უკვე გამოიყენა პარტია და commit-ა სამიზნე ტრანზაქცია.

cursor  = durable_checkpoint()          # last fully applied position
batch   = extract(cursor, upper_bound)  # one consistent batch
apply(batch)                            # idempotent at the target
commit()
checkpoint(batch.upper_bound)           # only now

თუ მიწოდება ნახევარგზაზე ჩავარდა, შეაჯერეთ იგივე პარტია და ნუ გამოიგონებთ ახალ წყაროს პოზიციას. უფრო ახალი ზედა საზღვრით ხელახალი ამოღება ის გზაა, რომლითაც ნაწილობრივი გამოყენება მუდმივ ხვრელად იქცევა. სარკის წესი მეორე მხარესაც მოქმედებს: სამიზნეზე იდემპოტენტური გამოყენება ხელს უშლის დუბლიკატებს და არაფერს აკეთებს იმ ცვლილებისთვის, რომელიც ამოღებას არასოდეს უნახავს.

წაშლებს ჩანაწერები სჭირდება, არა დასკვნები

ჯერ კიდევ არსებული სტრიქონების შედარება ვერ ეტყვის მომხმარებელს, რომელი კლავიშები გაქრნენ. წყარო, რომელიც არასოდეს აღრიცხავს წაშლებს, ორ არასრულ ვარიანტს გიტოვებთ: შეინახოთ კლავიშების ისტორია diff-ისთვის საკმარისად დიდხანს, ან გრაფიკის მიხედვით გაუშვათ გამოკვეთილი სრული შეჯერება. ორივე ხარჯიანი დიზაინის გადაწყვეტილებაა და არც ერთი არ არსებობს, თუ ვინმე არ ფლობს მას.

შენახვაც იგივე სახის გადაწყვეტილებაა. ყველა მხარდაჭერილ ცვლილებების ნაკადს აქვს ფანჯარა; განაცხადეთ ის ხელშეკრულებაში და გააფრთხილეთ, როცა მომხმარებლის საკონტროლო წერტილი მას უახლოვდება. ორკვირიანი შეწყვეტის შემდეგ გამოღვიძებულმა მომხმარებელმა უნდა წაიკითხოს მკაფიო შეცდომა "საჭიროა ხელახალი ინიციალიზაცია" და არა ჩუმად მიიღოს ნაწილობრივი პარტია.

შემდეგ გაზომეთ, ღირდა თუ არა დელტა

ყოველი კლავიშისა და hash-ის შედარებაზე დაბრუნება ზოგჯერ სწორია და ღირს იცოდეთ, რა ჯდება. თქვენ კვლავ გადასცემთ ინფორმაციას ყოველ სტრიქონზე, hash-ები არ გაძლევთ ცხრილებს შორის თანმიმდევრულ snapshot-ს და hash-ის სქემა მოაქვს საკუთარი კითხვები წარმოდგენასა და შეჯახებებზე. ნაკლები ბაიტი შესამოწმებელი საზღვრით არის მიზანი; ნაკლები ბაიტი, რომელიც ჩუმად კარგავს commit-ულ ცვლილებას, საერთოდ არ არის დელტა.

ბოლო ცვლილების სვეტი მინიშნებაა. კურსორი, რომელიც გადაიტანს გვიან commit-ს, წაშლას და გრძელ შეწყვეტას, ხელშეკრულებაა.

დაკავშირებული სტატიები