এসকিউএল সার্ভার: ছোট ছোট খণ্ডগুলিতে বিশাল টেবিলের ক্ষেত্রগুলি আপডেট করা: কীভাবে অগ্রগতি / স্ট্যাটাস পাবেন?


10

আমাদের একটি খুব বড় (100 মিলিয়ন সারি) টেবিল রয়েছে এবং এটিতে আমাদের কয়েকটি ক্ষেত্র আপডেট করতে হবে।

লগ শিপিং ইত্যাদির জন্য আমরা অবশ্যই স্পষ্টতই এটিকে কাটা-আকারের লেনদেনের মধ্যে রাখতে চাই।

  • নীচে কি কৌতুক করবে?
  • এবং আমরা কীভাবে এটি কিছু আউটপুট মুদ্রণ করতে পারি, যাতে আমরা অগ্রগতি দেখতে পারি? (আমরা সেখানে একটি PRINT বিবৃতি যোগ করার চেষ্টা করেছি, তবে লুপ চলাকালীন কিছুই আউটপুট ছিল না)

কোডটি হ'ল:

DECLARE @CHUNK_SIZE int
SET @CHUNK_SIZE = 10000

UPDATE TOP(@CHUNK_SIZE) [huge-table] set deleted = 0, deletedDate = '2000-01-01'
where deleted is null or deletedDate is null

WHILE @@ROWCOUNT > 0
BEGIN
    UPDATE TOP(@CHUNK_SIZE) [huge-table] set deleted = 0, deletedDate = '2000-01-01'
    where deleted is null or deletedDate is null
END

উত্তর:


12

সম্পর্কিত প্রশ্নটির উত্তর দেওয়ার সময় আমি এই প্রশ্ন সম্পর্কে অবগত ছিলাম না ( লুপ করার সময় এগুলিতে কি স্পষ্ট লেনদেনের প্রয়োজন? ), তবে সম্পূর্ণতার স্বার্থে, আমি এই সমস্যাটি এখানে এখানে সম্বোধন করব কারণ এটি সেই লিঙ্কযুক্ত উত্তরে আমার পরামর্শের অংশ ছিল না ।

যেহেতু আমি এসকিউএল এজেন্ট কাজের মাধ্যমে এটি নির্ধারণ করার পরামর্শ দিচ্ছি (এটি সর্বোপরি 100 মিলিয়ন সারি), আমি মনে করি না যে ক্লায়েন্টকে (যেমন এসএসএমএস) স্থিতি বার্তা প্রেরণের কোনও ফর্ম আদর্শ হবে (যদিও তা যদি হয়) অন্য প্রকল্পগুলির জন্য সর্বদা প্রয়োজন হয়, তবে আমি ভ্লাদিমিরের সাথে একমত হই যে ব্যবহার RAISERROR('', 10, 1) WITH NOWAIT;করা উপায় the

এই বিশেষ ক্ষেত্রে, আমি একটি স্ট্যাটাস টেবিল তৈরি করব যা এ পর্যন্ত আপডেট করা সারিগুলির সংখ্যা সহ প্রতিটি লুপে আপডেট করা যেতে পারে। এবং প্রক্রিয়াটিতে হার্ট বিট পেতে বর্তমান সময়ে ছোঁড়াতে আঘাত লাগে না।

প্রদত্ত যে আপনি প্রক্রিয়াটি বাতিল এবং পুনরায় চালু করতে সক্ষম হতে চান, আমি স্পষ্ট লেনদেনে স্থিতি সারণীর আপডেটের সাথে মুখ্য টেবিলের হালনাগাদটি लपेटতে ক্লান্ত am তবে, আপনি যদি মনে করেন যে স্থিতির টেবিলটি বাতিল হওয়ার কারণে কোনও সময়ের সাথে সিঙ্কের বাইরে চলে গেছে, কেবলমাত্র মানটির সাথে ম্যানুয়ালি আপডেট করে বর্তমান মানটি রিফ্রেশ করা সহজ COUNT(*) FROM [huge-table] WHERE deleted IS NOT NULL AND deletedDate IS NOT NULLএবং আপডেটের জন্য দুটি টেবিল রয়েছে (যেমন মূল টেবিল এবং স্থিতি সারণী), আমাদের সেই দুটি টেবিল সিঙ্কে রাখার জন্য একটি স্পষ্ট লেনদেন ব্যবহার করা উচিত , তবুও আপনি যদি কোনও প্রক্রিয়া বাতিল করেন তবে আমরা অনাথ লেনদেনের ঝুঁকি নিতে চাই না এটি লেনদেন শুরু হওয়ার পরেও এটি প্রতিশ্রুতিবদ্ধ হয়নি point যতক্ষণ আপনি এসকিউএল এজেন্ট কাজ বন্ধ না করেন এটি করা নিরাপদ হওয়া উচিত।

আপনি কীভাবে প্রক্রিয়াটি থামাতে পারবেন না? এটি বন্ধ করে জিজ্ঞাসা করে :-)। হাঁ। প্রক্রিয়াটিকে একটি "সিগন্যাল" ( kill -3ইউনিক্সের অনুরূপ ) প্রেরণ করে আপনি অনুরোধ করতে পারেন এটি পরবর্তী সুবিধাজনক মুহূর্তে বন্ধ করার জন্য (যেমন কোনও সক্রিয় লেনদেন নেই যখন!) এবং এটি সমস্ত সুন্দর এবং পরিপাটি-মত নিজেকে পরিষ্কার করতে অনুরোধ করতে পারে।

অন্য সেশনে চলমান প্রক্রিয়াটির সাথে আপনি কীভাবে যোগাযোগ করতে পারেন? এটির বর্তমান অবস্থাটি আপনার কাছে ফিরে যোগাযোগ করার জন্য আমরা এটির জন্য তৈরি করেছি একই পদ্ধতিটি ব্যবহার করে: স্থিতি সারণী। আমাদের কেবল একটি কলাম যুক্ত করতে হবে যা প্রক্রিয়াটি প্রতিটি লুপের শুরুতে যাচাই করবে যাতে এটি জেনে যায় বা অগ্রাহ্য করতে হবে কিনা knows আর যেহেতু অভিপ্রায়টি এসকিউএল এজেন্ট কাজ হিসাবে এটি নির্ধারণ করা হয় (প্রতি 10 বা 20 মিনিটের মধ্যে চালানো হয়), প্রক্রিয়াটি কেবল চলতে থাকলে 1 মিলিয়ন সারি দিয়ে একটি টেম্প টেবিলটি পূরণ করার কোনও অর্থ নেই বলে আমাদেরও খুব প্রথম দিকে পরীক্ষা করা উচিত we এক মুহুর্ত পরে প্রস্থান করতে এবং সেই ডেটার কোনওটিই ব্যবহার না করা।

DECLARE @BatchRows INT = 1000000,
        @UpdateRows INT = 4995;

IF (OBJECT_ID(N'dbo.HugeTable_TempStatus') IS NULL)
BEGIN
  CREATE TABLE dbo.HugeTable_TempStatus
  (
    RowsUpdated INT NOT NULL, -- updated by the process
    LastUpdatedOn DATETIME NOT NULL, -- updated by the process
    PauseProcess BIT NOT NULL -- read by the process
  );

  INSERT INTO dbo.HugeTable_TempStatus (RowsUpdated, LastUpdatedOn, PauseProcess)
  VALUES (0, GETDATE(), 0);
END;

-- First check to see if we should run. If no, don't waste time filling temp table
IF (EXISTS(SELECT * FROM dbo.HugeTable_TempStatus WHERE PauseProcess = 1))
BEGIN
  PRINT 'Process is paused. No need to start.';
  RETURN;
END;

CREATE TABLE #FullSet (KeyField1 DataType1, KeyField2 DataType2);
CREATE TABLE #CurrentSet (KeyField1 DataType1, KeyField2 DataType2);

INSERT INTO #FullSet (KeyField1, KeyField2)
  SELECT TOP (@BatchRows) ht.KeyField1, ht.KeyField2
  FROM   dbo.HugeTable ht
  WHERE  ht.deleted IS NULL
  OR     ht.deletedDate IS NULL

WHILE (1 = 1)
BEGIN
  -- Check if process is paused. If yes, just exit cleanly.
  IF (EXISTS(SELECT * FROM dbo.HugeTable_TempStatus WHERE PauseProcess = 1))
  BEGIN
    PRINT 'Process is paused. Exiting.';
    BREAK;
  END;

  -- grab a set of rows to update
  DELETE TOP (@UpdateRows)
  FROM   #FullSet
  OUTPUT Deleted.KeyField1, Deleted.KeyField2
  INTO   #CurrentSet (KeyField1, KeyField2);

  IF (@@ROWCOUNT = 0)
  BEGIN
    RAISERROR(N'All rows have been updated!!', 16, 1);
    BREAK;
  END;

  BEGIN TRY
    BEGIN TRAN;

    -- do the update of the main table
    UPDATE ht
    SET    ht.deleted = 0,
           ht.deletedDate = '2000-01-01'
    FROM   dbo.HugeTable ht
    INNER JOIN #CurrentSet cs
            ON cs.KeyField1 = ht.KeyField1
           AND cs.KeyField2 = ht.KeyField2;

    -- update the current status
    UPDATE ts
    SET    ts.RowsUpdated += @@ROWCOUNT,
           ts.LastUpdatedOn = GETDATE()
    FROM   dbo.HugeTable_TempStatus ts;

    COMMIT TRAN;
  END TRY
  BEGIN CATCH
    IF (@@TRANCOUNT > 0)
    BEGIN
      ROLLBACK TRAN;
    END;

    THROW; -- raise the error and terminate the process
  END CATCH;

  -- clear out rows to update for next iteration
  TRUNCATE TABLE #CurrentSet;

  WAITFOR DELAY '00:00:01'; -- 1 second delay for some breathing room
END;

-- clean up temp tables when testing
-- DROP TABLE #FullSet; 
-- DROP TABLE #CurrentSet; 

তারপরে আপনি নিম্নলিখিত কোয়েরিটি ব্যবহার করে যে কোনও সময় স্থিতিটি পরীক্ষা করতে পারেন:

SELECT sp.[rows] AS [TotalRowsInTable],
       ts.RowsUpdated,
       (sp.[rows] - ts.RowsUpdated) AS [RowsRemaining],
       ts.LastUpdatedOn
FROM sys.partitions sp
CROSS JOIN dbo.HugeTable_TempStatus ts
WHERE  sp.[object_id] = OBJECT_ID(N'ResizeTest')
AND    sp.[index_id] < 2;

প্রক্রিয়াটি বিরতি দিতে চান, এটি কোনও এসকিউএল এজেন্ট চাকরিতে বা অন্য কারও কম্পিউটারে এসএসএমএসে চলছে কিনা? শেষ ঘন্টা:

UPDATE ht
SET    ht.PauseProcess = 1
FROM   dbo.HugeTable_TempStatus ts;

প্রক্রিয়াটি আবার ব্যাক আপ শুরু করতে সক্ষম হতে চান? শেষ ঘন্টা:

UPDATE ht
SET    ht.PauseProcess = 0
FROM   dbo.HugeTable_TempStatus ts;

হালনাগাদ:

চেষ্টা করার জন্য এখানে অতিরিক্ত কিছু জিনিস রয়েছে যা এই ক্রিয়াকলাপটির কার্যকারিতা উন্নত করতে পারে। কারওরও সহায়তার নিশ্চয়তা নেই তবে সম্ভবত এটি পরীক্ষার উপযুক্ত। এবং আপডেট করার জন্য 100 মিলিয়ন সারি সহ, আপনার কাছে কিছু বৈচিত্র্য পরীক্ষা করার জন্য প্রচুর সময় / সুযোগ রয়েছে ;-)।

  1. যোগ TOP (@UpdateRows)আপডেট কোয়েরি যাতে মত শীর্ষ লাইন দেখায়:
    UPDATE TOP (@UpdateRows) ht
    কখনও কখনও এটি অপটিমাইজার জানেন যে কত সারি সর্বোচ্চ তাই এটি সময় নষ্ট করবেন না খুঁজছেন আরো প্রভাবিত হবে সাহায্য করে।
  2. #CurrentSetঅস্থায়ী সারণীতে একটি প্রাথমিক কী যুক্ত করুন । এখানে ধারণাটি হ'ল 100 মিলিয়ন সারি সারণিতে JOIN এর সাহায্যে অপ্টিমাইজারটিকে সহায়তা করা।

    অস্পষ্ট না হওয়ার জন্য এটি কেবল বিবৃত করার জন্য, #FullSetঅস্থায়ী টেবিলটিতে কোনও পিকে যুক্ত করার কোনও কারণ থাকতে হবে না কারণ এটি কেবল একটি সারি সারণি যেখানে আদেশ অপ্রাসঙ্গিক।

  3. কিছু ক্ষেত্রে এটি অস্থির টেবিলের SELECTমধ্যে ফিডগুলি সহায়তা করতে একটি ফিল্টার সূচক যুক্ত করতে সহায়তা করে #FullSet। এই জাতীয় সূচক যুক্ত করার সাথে সম্পর্কিত কিছু বিবেচনা এখানে দেওয়া হয়েছে:
    1. আপনার কোয়েরীর শর্তটির সাথে WHERE শর্তটি মিলবে WHERE deleted is null or deletedDate is null
    2. প্রক্রিয়াটির শুরুতে, বেশিরভাগ সারিগুলি আপনার WHERE অবস্থার সাথে মিলবে, সুতরাং কোনও সূচকটি তেমন সহায়ক নয়। এটি যুক্ত করার আগে আপনি প্রায় 50% চিহ্নের আশেপাশে অপেক্ষা করতে চাইতে পারেন। অবশ্যই, এটি কতটা সহায়তা করে এবং যখন সূচক যুক্ত করা ভাল তখন বেশ কয়েকটি কারণের কারণে পরিবর্তিত হয়, তাই এটি কিছুটা পরীক্ষা এবং ত্রুটি।
    3. বেস ডেটা বেশ ঘন ঘন পরিবর্তিত হবার কারণে আপনাকে ম্যানুয়ালি স্ট্যাটস আপডেট করতে এবং / অথবা সূচিটি আপ টু ডেট রাখতে হবে might
    4. মনে রাখতে ভুলবেন না যে সূচকে, সহায়তা করার সময় SELECT, এটি ক্ষতিগ্রস্থ করবে UPDATEযেহেতু এটি অপারেশন চলাকালীন আপডেট হওয়া আবশ্যক, সুতরাং আরও I / O। এটি একটি ফিল্টার সূচক (যেগুলি কম সারিগুলি ফিল্টারটির সাথে মিলিত হওয়ার সাথে সাথে সারিগুলি আপডেট করার সাথে সাথে সঙ্কুচিত হয়) ব্যবহার করে উভয়ের মধ্যে খেলবে এবং সূচি যোগ করতে কিছুক্ষণ অপেক্ষা করতে হবে (যদি এটি শুরুতে সুপার সহায়ক না হয়, তবে ব্যয় করার কোনও কারণ নেই) অতিরিক্ত আই / ও)।

1
এটি দুর্দান্ত। আমি এখন এটি চালাচ্ছি, এবং এটি স্মোক করে যে আমরা দিনের বেলা লাইনে এটি চালাতে পারি। ধন্যবাদ!
জোনসোম পুনরায় ইনস্টল করুন মনিকা

@ স্যামস্মিথ দয়া করে প্রক্রিয়াটিকে আরও দ্রুততর করার জন্য কিছু ধারণা রয়েছে বলে আমি আপডেট করা অংশটি দেখুন just
সলোমন রুটজকি

আপডেট আপডেট না করে, আমরা প্রায় 8 মিলিয়ন আপডেট / ঘন্টা পাচ্ছি ... @BatchRows 10000000 (দশ মিলিয়ন) এ সেট করে
জোনসোম রিইনস্টেট মনিকা

@ স্যামস্মিথ দারুণ :) ঠিক আছে তো? দুটি বিষয় মনে রাখবেন: ১) প্রক্রিয়াটি ধীরে ধীরে হ্রাস পাবে যেখানে নিখরচায় অনুচ্ছেদটি কম এবং কম সারি মিলেছে, সুতরাং ফিল্টারড সূচক যুক্ত করার জন্য কেন এটি ভাল সময় হবে তবে আপনি ইতিমধ্যে একটি ফিল্টারবিহীন সূচক যুক্ত করেছেন শুরু করুন তবে আমি নিশ্চিত নই যে এটি সাহায্য করবে বা আঘাত করবে কিনা, তবে এখনও আমি আশা করব যে থ্রুপুটটি এটি সম্পন্ন হওয়ার কাছাকাছি আসার সাথে সাথে হ্রাস পাবে এবং ২) আপনি আধা সেকেন্ড বা ততোধিক হ্রাস করে থ্রুপুটটি বাড়িয়ে দিতে পারবেনWAITFOR DELAY , তবে এটি সম্মতিযুক্ত একটি লেনদেন এবং সম্ভবত লগ-শিপিংয়ের মাধ্যমে কত পাঠানো হয়।
সলোমন রুটজকি

আমরা 8 মিলিয়ন সারি / ঘন্টা নিয়ে খুশি। হ্যাঁ, আমরা এটিকে কমে যেতে দেখছি। আমরা আর কোনও সূচক তৈরি করতে দ্বিধা বোধ করছি (কারণ টেবিলটি পুরো বিল্ডের জন্য লক করা আছে)। আমরা দু'বার যা করেছি তা হ'ল বিদ্যমান সূচকে পুনরায় কাজ করা (কারণ এটি লাইনে রয়েছে)।
জোনসোম পুনরায় ইনস্টল করুন মনিকা

4

দ্বিতীয় অংশের উত্তর দেওয়া: লুপ চলাকালীন কিছু আউটপুট কীভাবে প্রিন্ট করা যায়।

আমার বেশ কয়েকটি দীর্ঘ-চলমান রক্ষণাবেক্ষণ পদ্ধতি রয়েছে যা প্রশাসনের মাঝে মাঝে পরিচালনা করতে হয়।

আমি তাদের এসএসএমএস থেকে চালিত করেছি এবং লক্ষ্য করেছি যে PRINTসম্পূর্ণ পদ্ধতি শেষ হওয়ার পরে এসএসএমএসে বিবৃতি প্রদর্শিত হবে।

সুতরাং, আমি RAISERRORকম তীব্রতার সাথে ব্যবহার করছি :

DECLARE @VarTemp nvarchar(32);
SET @VarTemp = CONVERT(nvarchar(32), GETDATE(), 121);
RAISERROR (N'Your message. Current time is %s.', 0, 1, @VarTemp) WITH NOWAIT;

আমি এসকিউএল সার্ভার 2008 স্ট্যান্ডার্ড এবং এসএসএমএস 2012 (11.0.3128.0) ব্যবহার করছি। এসএসএমএসে চালানোর জন্য এখানে একটি সম্পূর্ণ কার্যকারী উদাহরণ:

DECLARE @VarCount int = 0;
DECLARE @VarTemp nvarchar(32);

WHILE @VarCount < 3
BEGIN
    SET @VarTemp = CONVERT(nvarchar(32), GETDATE(), 121);
    --RAISERROR (N'Your message. Current time is %s.', 0, 1, @VarTemp) WITH NOWAIT;
    --PRINT @VarTemp;

    WAITFOR DELAY '00:00:02';
    SET @VarCount = @VarCount + 1;
END

যখন আমি মন্তব্য করি এবং এসএসএমএসের বার্তাগুলি ট্যাবে RAISERRORকেবলমাত্র PRINTবার্তাগুলি পুরো ব্যাচটি শেষ হওয়ার পরে, 6 সেকেন্ড পরে উপস্থিত হয়।

যখন আমি মন্তব্য করি এবং এসএসএমএসে বার্তাগুলি ট্যাবে বার্তাগুলি PRINTব্যবহার করি তখন RAISERROR6 সেকেন্ড অপেক্ষা না করে উপস্থিত হয়, তবে লুপের অগ্রগতি হিসাবে।

মজার বিষয় হল, যখন আমি উভয় ব্যবহার করি RAISERRORএবং PRINT, আমি উভয় বার্তা দেখি। প্রথমে প্রথম বার্তা আসে RAISERROR, তারপরে 2 সেকেন্ডের জন্য বিলম্ব করুন, তারপরে প্রথম PRINTএবং দ্বিতীয় RAISERRORএবং আরও অনেক কিছু।


অন্যান্য ক্ষেত্রে আমি একটি পৃথক উত্সর্গীকৃত logটেবিল ব্যবহার করি এবং দীর্ঘমেয়াদী প্রক্রিয়াটির বর্তমান অবস্থা এবং টাইমস্ট্যাম্প বর্ণনা করে কিছু তথ্য সহ কেবল সারণিতে একটি সারি সন্নিবেশ করি।

দীর্ঘ প্রক্রিয়াটি চলাকালীন সময়ে সময়ে টেবিল SELECTথেকে আমি logকী চলছে তা দেখার জন্য।

স্পষ্টত এটির কিছু নির্দিষ্ট ওভারহেড রয়েছে তবে এটি একটি লগ (বা লগের ইতিহাস) ছেড়ে দেয় যা আমি পরে নিজের গতিতে পরীক্ষা করতে পারি।


এসকিউএল ২০০৮/২০১৪ এ, আমরা উত্থাপনকারী থেকে ফলাফল দেখতে পাচ্ছি না .... আমরা কী মিস করছি?
জোনসোম পুনরায় ইনস্টল করুন মনিকা

@ স্যামস্মিথ, আমি একটি সম্পূর্ণ উদাহরণ যুক্ত করেছি। চেষ্টা করে দেখুন এই সাধারণ উদাহরণে আপনি কী আচরণ পেতে পারেন?
ভ্লাদিমির বারানভ

2

আপনি এটির মতো অন্য কোনও সংযোগ থেকে এটি পর্যবেক্ষণ করতে পারেন:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT COUNT(*) FROM [huge-table] WHERE deleted IS NULL OR deletedDate IS NULL 

কত কিছু বাকি আছে তা দেখতে। আপনি যদি এসএসএমএসে বা অনুরূপভাবে ম্যানুয়ালি চালনার পরিবর্তে কোনও অ্যাপ্লিকেশন প্রক্রিয়াটি কল করে থাকেন এবং এটি অগ্রগতি দেখানোর প্রয়োজন হয় তবে এটি কার্যকর হতে পারে: মূল প্রক্রিয়াটি অ্যাসিঙ্ক্রোনালি (বা অন্য কোনও থ্রেডে) চালনা করুন এবং তারপরে "কতটা বাকি আছে" লুপ কল করুন "যতক্ষণ না অ্যাসিঙ্ক কল (বা থ্রেড) সম্পূর্ণ হয় ততক্ষণ প্রতিবার দেখুন।

বিচ্ছিন্নতা স্তরটিকে যথাসম্ভব শিথিলকরণের অর্থ হ'ল লকিংয়ের কারণে মূল লেনদেনের পিছনে আটকে না রেখে যুক্তিসঙ্গত সময়ে এটি ফিরে আসা উচিত। এর অর্থ হতে পারে যে প্রত্যাবর্তিত মানটি অবশ্যই কিছুটা ভুল c তবে একটি সাধারণ অগ্রগতি মিটার হিসাবে এটি মোটেই গুরুত্বপূর্ণ নয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.