এসকিউএল সার্ভারে অন্তর্ভুক্ত বা আপডেটের সমাধান


596

একটি সারণী কাঠামো ধরে নিন MyTable(KEY, datafield1, datafield2...)

প্রায়শই আমি হয় হয় বিদ্যমান রেকর্ড আপডেট করতে চাইছি, বা এটি উপস্থিত না থাকলে একটি নতুন রেকর্ড সন্নিবেশ করতে চাই।

মূলত:

IF (key exists)
  run update command
ELSE
  run insert command

এটি লেখার সর্বোত্তম পারফরম্যান্স কী?



26
এই প্রশ্নটি প্রথমবারের মতো যে কেউ আসছেন - তার জন্য দয়া করে সমস্ত উত্তর এবং তাদের মন্তব্যগুলি পড়তে ভুলবেন না। বয়স কখনও কখনও বিভ্রান্তিকর তথ্যের দিকে নিয়ে যেতে পারে ...
অ্যারন বারট্রান্ড

1
এক্সসিপিটি অপারেটরটি ব্যবহারের কথা বিবেচনা করুন, যা এসকিউএল সার্ভার 2005
টারজান

উত্তর:


370

লেনদেন সম্পর্কে ভুলবেন না পারফরম্যান্স ভাল, তবে সহজ (যদি উপস্থিত থাকে ..) পদ্ধতিটি খুব বিপজ্জনক।
যখন একাধিক থ্রেড সন্নিবেশ-বা আপডেট সম্পাদন করার চেষ্টা করবে আপনি সহজেই প্রাথমিক কী লঙ্ঘন পেতে পারেন।

@ বিউ ক্র্যাফোর্ড এবং @ ইস্তবান দ্বারা প্রদত্ত সমাধানগুলি সাধারণ ধারণাটি দেখায় তবে ত্রুটি-প্রবণ।

ডেডলকস এবং পিকে লঙ্ঘন এড়াতে আপনি এরকম কিছু ব্যবহার করতে পারেন:

begin tran
if exists (select * from table with (updlock,serializable) where key = @key)
begin
   update table set ...
   where key = @key
end
else
begin
   insert into table (key, ...)
   values (@key, ...)
end
commit tran

অথবা

begin tran
   update table with (serializable) set ...
   where key = @key

   if @@rowcount = 0
   begin
      insert into table (key, ...) values (@key,..)
   end
commit tran

সবচেয়ে সুরক্ষিত সমাধানের চেয়ে প্রশ্নটি সবচেয়ে পারফরম্যান্স সমাধানের জন্য জিজ্ঞাসা করেছিল। কোনও লেনদেন প্রক্রিয়াতে সুরক্ষা যুক্ত করার সাথে সাথে এটি একটি ওভারহেডও যুক্ত করে।
লুক বেনেট

31
এই দুটি পদ্ধতিই এখনও ব্যর্থ হতে পারে। যদি একই সারিতে দুটি সমবর্তী থ্রেড একই কাজ করে তবে প্রথমটি সফল হবে তবে প্রাথমিক কী লঙ্ঘনের কারণে দ্বিতীয় সন্নিবেশ ব্যর্থ হবে। কোনও লেনদেন গ্যারান্টি দেয় না যে রেকর্ডটি বিদ্যমান থাকার কারণে আপডেট ব্যর্থ হলেও সন্নিবেশ সফল হবে will গ্যারান্টির জন্য যে কোনও সংখ্যক সাম্প্রতিক লেনদেন সফল হবে আপনার একটি লক ব্যবহার করা উচিত।
জিন ভিনসেন্ট

7
@ একিউ আপনি যে কোনও কারণে টেবিল ইঙ্গিত ব্যবহার করেছেন ("(xxxx)" সহ) আপনার "বিগইন ট্রানের ঠিক আগে" ট্রান্সএকশন বিচ্ছিন্নতা স্তর সেরিয়ালজিবল "এর বিপরীতে?
EBarr

4
@ ক্যাশকো, সর্বশেষ বিজয়ী, এটিই অন্তর্ভুক্ত বা আপডেটের কথা বলেছে: প্রথমটি সন্নিবেশ করায়, দ্বিতীয়টি রেকর্ডটি আপডেট করে। একটি লক যুক্ত করা একটি ত্রুটি রোধ করে খুব স্বল্প সময়ের ফ্রেমে এটি হতে দেয়।
জিন ভিনসেন্ট

1
আমি সবসময় ভেবেছিলাম ব্যবহারের লকিংয়ের ইঙ্গিতগুলি খারাপ and এটাই কি নিয়মের আপাত ব্যতিক্রম?

381

খুব অনুরূপ পূর্ববর্তী প্রশ্নের আমার বিস্তারিত উত্তর দেখুন

এসিকিউএল 2005 এবং এর নিচে @ বিউ ক্র্যাফোর্ডের একটি ভাল উপায়, যদিও আপনি যদি প্রতিলিপি প্রদান করেন তবে এটি প্রথম লোকের কাছে এটি হওয়া উচিত । একমাত্র সমস্যা হ'ল সন্নিবেশকারীদের জন্য এটি এখনও দুটি আইও অপারেশন।

এমএস mergeএসকিউএল ২০০৮ এসকিউএল: 2003 স্ট্যান্ডার্ড থেকে পরিচয় করিয়েছে :

merge tablename with(HOLDLOCK) as target
using (values ('new value', 'different value'))
    as source (field1, field2)
    on target.idfield = 7
when matched then
    update
    set field1 = source.field1,
        field2 = source.field2,
        ...
when not matched then
    insert ( idfield, field1, field2, ... )
    values ( 7,  source.field1, source.field2, ... )

এখন এটি কেবলমাত্র একটি আইও অপারেশন, তবে ভয়াবহ কোড :-(


10
@ ইয়ান বয়ড - হ্যাঁ, এটি এসকিউএল: ২০০৩ স্ট্যান্ডার্ডের বাক্য গঠন, upsertঅন্য সমস্ত ডিবি সরবরাহকারীরা পরিবর্তে সমর্থন করার সিদ্ধান্ত নিয়েছে তা নয়। upsertসিনট্যাক্স এই কাজ করতে একটি পর্যন্ত সুন্দর ভাবে যাতে অন্ততপক্ষে মাইক্রোসফট এ এটা খুব সমর্থিত উচিত, - এটা শুধুমাত্র টি-SQL এর যে অ মান শব্দ মত নয়
কিথ

1
অন্যান্য উত্তরে লক ইঙ্গিতে কোনও মন্তব্য? (শীঘ্রই এটি সন্ধান করতে হবে, তবে এটি যদি প্রস্তাবিত উপায় হয় তবে আমি উত্তরে এটি যুক্ত করার পরামর্শ দিই)
এলাশিয়াস

25
সিনট্যাক্স ব্যবহার করার পরেও যে সমস্যাগুলি হতে পারে ত্রুটি সৃষ্টি হতে পারে তা থেকে কীভাবে জাতিদের পরিস্থিতি রোধ করা যায় তার উত্তরের জন্য এখানে ওয়েবলগস.সাক্লিটএইম / ড্যাং / অর্চিভ / ২০০৯/ 01/31/… দেখুন MERGE
Seph

5
@ সেফ এটি একটি সত্যই আশ্চর্য - মাইক্রোসফ্টের কিছুটা ব্যর্থতা এখানে রয়েছে: এসআই অনুমান যে এর অর্থ আপনার HOLDLOCKউচ্চ সম্মতিযুক্ত পরিস্থিতিতে মার্জ অপারেশনগুলির জন্য প্রয়োজন ।
কিথ

11
এই উত্তরটি হোল্ডলক ব্যতীত থ্রেড-নিরাপদ না হওয়া সম্পর্কে সেফের মন্তব্যের জন্য অ্যাকাউন্টটির আপডেট হওয়ার প্রয়োজন। লিঙ্কযুক্ত পোস্ট অনুসারে, MERGE স্পষ্টতই একটি আপডেট লক বের করে, তবে সারি সন্নিবেশ করার আগে এটি প্রকাশ করে, যা সন্নিবেশের সময় একটি বর্ণের শর্ত এবং প্রাথমিক কী লঙ্ঘনের কারণ হতে পারে। হোল্ডলক ব্যবহার করে, লকগুলি সন্নিবেশ না হওয়া পর্যন্ত রাখা হয়।
ট্রায়ঙ্কো

169

একটি ইউএসইআরটি করুন:

MyTable SET FieldA = @ FieldA WHERE কী = @ কী আপডেট করুন

যদি @@ ROWCOUNT = 0
   মাই টেবিল (ফিল্ডা) ভ্যালুতে অন্তর্ভুক্ত করুন (@ ফিল্ডা)

http://en.wikipedia.org/wiki/Upsert


7
আপনার যদি যথাযথ অনন্য সূচক সীমাবদ্ধতা প্রয়োগ করে তবে প্রাথমিক কী লঙ্ঘন হওয়া উচিত নয়। সীমাবদ্ধতার পুরো বিষয়টি হ'ল ডুপ্লিকেট সারিগুলিকে প্রতিটি ঘটনাকে প্রতিরোধ করা। কতগুলি থ্রেড inোকানোর চেষ্টা করছে তা বিবেচনাধীন নয়, সীমাবদ্ধতা প্রয়োগের জন্য ডাটাবেসটি প্রয়োজনীয়ভাবে সিরিয়ালাইজ করবে ... এবং যদি তা না হয় তবে ইঞ্জিনটি মূল্যহীন। অবশ্যই, এটি সিরিয়ালযুক্ত লেনদেনে মোড়ানো এটিকে আরও সঠিক এবং ডেডলক বা ব্যর্থ সন্নিবেশগুলিতে কম সংবেদনশীল করে তুলবে।
ত্রিণকো

19
@Triynko, আমি মনে করি @Sam জাফরান অর্থ যদি দুটি + + থ্রেড অধিকার ক্রমানুসারে বইয়ের পাতার মাঝে মাঝে তারপর SQL সার্ভার হবে নিক্ষেপ একটি প্রাথমিক কী লঙ্ঘন ইঙ্গিত একটি ত্রুটি যেত ঘটেছে। এটিকে সিরিয়ালেজযোগ্য লেনদেনে মুড়ে ফেলা হ'ল উপরের বক্তব্যগুলির সেটগুলির ত্রুটিগুলি রোধ করার সঠিক উপায়।
EBarr

1
এমনকি যদি আপনার কাছে একটি প্রাথমিক কী থাকে যা স্বতঃবৃদ্ধি হয় তবে আপনার উদ্বেগের পরে কোনও অনন্য বাধা থাকবে যা টেবিলে থাকতে পারে।
Seph

1
ডাটাবেসটি প্রাথমিক কী সমস্যাগুলির যত্ন নেওয়া উচিত। আপনি যা বলছেন তা হ'ল যদি আপডেট ব্যর্থ হয় এবং inোকানোর সাথে প্রথমে অন্য প্রক্রিয়াটি আসে তবে আপনার yourোকানো ব্যর্থ হবে। সেক্ষেত্রে আপনার যেভাবেই হোক রেসের শর্ত রয়েছে। লকিংয়ের পরে এই অবস্থাটি পরিবর্তিত হবে না যে পোস্ট-শর্তটি লেখার চেষ্টা করে এমন একটি প্রক্রিয়াটির মান পাবে।
ক্যাশকো

93

অনেক লোক আপনাকে ব্যবহারের পরামর্শ দিবে MERGE, তবে আমি আপনাকে এর বিরুদ্ধে সাবধান করছি। ডিফল্টরূপে, এটি আপনাকে একাধিক বিবৃতি ছাড়া সামঞ্জস্য এবং বর্ণের পরিস্থিতি থেকে রক্ষা করে না, তবে এটি অন্যান্য বিপদগুলিরও পরিচয় দেয়:

http://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/

এমনকি এই "সরল" সিনট্যাক্সটি উপলব্ধ থাকা সত্ত্বেও আমি এখনও এই পদ্ধতির পছন্দ করি (ব্রেভিটির জন্য বাদ দেওয়া ত্রুটি পরিচালনা করে):

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
UPDATE dbo.table SET ... WHERE PK = @PK;
IF @@ROWCOUNT = 0
BEGIN
  INSERT dbo.table(PK, ...) SELECT @PK, ...;
END
COMMIT TRANSACTION;

অনেক লোক এইভাবে পরামর্শ দেবেন:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
IF EXISTS (SELECT 1 FROM dbo.table WHERE PK = @PK)
BEGIN
  UPDATE ...
END
ELSE
  INSERT ...
END
COMMIT TRANSACTION;

তবে এই সমস্ত সম্পাদনকারীরা নিশ্চিত করছে যে সারিটি আপডেট করার জন্য আপনাকে দুবার টেবিলটি পড়তে হবে। প্রথম নমুনায়, আপনাকে কেবল একবারই সারিটি সনাক্ত করতে হবে। (উভয় ক্ষেত্রেই, প্রাথমিক পাঠ থেকে কোনও সারি পাওয়া না গেলে, একটি সন্নিবেশ ঘটে occurs)

অন্যরা এইভাবে পরামর্শ দেবেন:

BEGIN TRY
  INSERT ...
END TRY
BEGIN CATCH
  IF ERROR_NUMBER() = 2627
    UPDATE ...
END CATCH

যাইহোক, এটি যদি সমস্যা হয় তবে এসকিউএল সার্ভারকে ব্যতিক্রমগুলি ধরতে দেওয়া ছাড়া যদি আপনি প্রথমে প্রতিরোধ করতে পারেন তবে এটি ব্যয়বহুল দৃশ্য ব্যতীত, যেখানে প্রায় প্রতিটি সন্নিবেশ ব্যর্থ হয় except আমি এখানে যতটা প্রমাণ করি:


3
অনেকগুলি রেকর্ড সন্নিবেশ করা / আপডেট করা কোনও টেম টেবিল থেকে FROM সন্নিবেশ / আপডেট করা সম্পর্কে কী?
ব্যবহারকারী 960567

@ ব্যবহারকারী960567 আচ্ছা,UPDATE target SET col = tmp.col FROM target INNER JOIN #tmp ON <key clause>; INSERT target(...) SELECT ... FROM #tmp AS t WHERE NOT EXISTS (SELECT 1 FROM target WHERE key = t.key);
অ্যারোন বার্ট্রান্ড

4
2 বছরেরও বেশি সময় পরে উত্তরে উত্তর দিয়েছেন :)
user960567

12
@ ব্যবহারকারী960567 দুঃখিত, আমি সবসময় আসল সময়ে মন্তব্য বিজ্ঞপ্তি ধরেন না।
অ্যারন বারট্রান্ড

60
IF EXISTS (SELECT * FROM [Table] WHERE ID = rowID)
UPDATE [Table] SET propertyOne = propOne, property2 . . .
ELSE
INSERT INTO [Table] (propOne, propTwo . . .)

সম্পাদনা:

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


6
আমি এখনও এটি আরও ভাল পছন্দ। উপস্থাপনাটি আরও বেশি পার্শ্ব প্রতিক্রিয়া অনুসারে প্রোগ্রামিংয়ের মতো বলে মনে হচ্ছে এবং সত্যিকারের ডাটাবেজে পারফরম্যান্সের সমস্যা দেখা দেওয়ার জন্য আমি প্রথমবারের মতো ছোট্ট ক্লাস্টারড সূচকটি খুঁজে পাইনি
এরিক জেড দাড়ি 1

38

আপনি যদি একবারে একাধিক রেকর্ড UPSERT করতে চান তবে আপনি এএনএসআই এসকিউএল: 2003 ডিএমএল বিবৃতিটি মার্জ ব্যবহার করতে পারেন।

MERGE INTO table_name WITH (HOLDLOCK) USING table_name ON (condition)
WHEN MATCHED THEN UPDATE SET column1 = value1 [, column2 = value2 ...]
WHEN NOT MATCHED THEN INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ...])

পরীক্ষা করে দেখুন SQL সার্ভার 2005 সালে অনুকারী একত্রীকরণ বিবৃতি


1
ওরাকল-এ, একটি মার্জ স্টেটমেন্ট জারি করে আমার মনে হয় টেবিলটি লক হয়ে গেছে। একই কি এসকিউএল * সার্ভারে ঘটে?
মাইক ম্যাকএলিস্টার

13
MERGE জাতিগত অবস্থার জন্য সংবেদনশীল ( ওয়েবলাগস.সক্লিটএইম / ড্যাং / অর্চিভ / ২০০৯ / ১ / ৩ / ৩ / দেখুন ) যদি না আপনি এটিকে সার্টিয়ান লক ধরে রাখেন। এছাড়াও, এসকিউএল প্রোফাইলার-এ MERGE এর পারফরম্যান্সের দিকে একবার নজর দিন ... আমি দেখতে পাচ্ছি যে এটি সাধারণত ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে হয় এবং বিকল্প সমাধানের চেয়ে আরও বেশি পাঠ উত্পন্ন করে।
EBarr

@ ইবার - লকগুলিতে লিঙ্কটির জন্য ধন্যবাদ। প্রস্তাবটি লক করার ইঙ্গিতটি অন্তর্ভুক্ত করার জন্য আমি আমার উত্তর আপডেট করেছি।
এরিক ওয়েলনাউ


10

যদিও এতে মন্তব্য করতে বেশ দেরি হয়ে গেছে আমি মার্জ ব্যবহার করে আরও একটি সম্পূর্ণ উদাহরণ যুক্ত করতে চাই।

এই জাতীয় সন্নিবেশ + আপডেট বিবৃতি সাধারণত "আপসার্ট" স্টেটমেন্ট বলা হয় এবং এসকিউএল সার্ভারে মার্জ ব্যবহার করে প্রয়োগ করা যেতে পারে।

একটি খুব ভাল উদাহরণ এখানে দেওয়া হয়: http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx

উপরোক্ত পাশাপাশি লকিং এবং একযোগিতাপূর্ণ পরিস্থিতিতেও ব্যাখ্যা করে।

আমি রেফারেন্সের জন্য একই উদ্ধৃতি করা হবে:

ALTER PROCEDURE dbo.Merge_Foo2
      @ID int
AS

SET NOCOUNT, XACT_ABORT ON;

MERGE dbo.Foo2 WITH (HOLDLOCK) AS f
USING (SELECT @ID AS ID) AS new_foo
      ON f.ID = new_foo.ID
WHEN MATCHED THEN
    UPDATE
            SET f.UpdateSpid = @@SPID,
            UpdateTime = SYSDATETIME()
WHEN NOT MATCHED THEN
    INSERT
      (
            ID,
            InsertSpid,
            InsertTime
      )
    VALUES
      (
            new_foo.ID,
            @@SPID,
            SYSDATETIME()
      );

RETURN @@ERROR;

1
MERGE নিয়ে উদ্বিগ্ন হওয়ার মতো আরও কিছু বিষয় রয়েছে: mssqltips.com/sqlservertip/3074/…
অ্যারন

8
/*
CREATE TABLE ApplicationsDesSocietes (
   id                   INT IDENTITY(0,1)    NOT NULL,
   applicationId        INT                  NOT NULL,
   societeId            INT                  NOT NULL,
   suppression          BIT                  NULL,
   CONSTRAINT PK_APPLICATIONSDESSOCIETES PRIMARY KEY (id)
)
GO
--*/

DECLARE @applicationId INT = 81, @societeId INT = 43, @suppression BIT = 0

MERGE dbo.ApplicationsDesSocietes WITH (HOLDLOCK) AS target
--set the SOURCE table one row
USING (VALUES (@applicationId, @societeId, @suppression))
    AS source (applicationId, societeId, suppression)
    --here goes the ON join condition
    ON target.applicationId = source.applicationId and target.societeId = source.societeId
WHEN MATCHED THEN
    UPDATE
    --place your list of SET here
    SET target.suppression = source.suppression
WHEN NOT MATCHED THEN
    --insert a new line with the SOURCE table one row
    INSERT (applicationId, societeId, suppression)
    VALUES (source.applicationId, source.societeId, source.suppression);
GO

সারণি এবং ক্ষেত্রের নামগুলি যা প্রয়োজন তা প্রতিস্থাপন করুন। ওএন শর্তটি ব্যবহারের যত্ন নিন । তারপরে ডেকলার লাইনে ভেরিয়েবলের জন্য উপযুক্ত মান (এবং টাইপ করুন) সেট করুন।

চিয়ার্স।


7

আপনি MERGEবিবৃতি ব্যবহার করতে পারেন , এই বিবৃতিটি উপস্থিত না থাকলে ডেটা toোকাতে বা উপস্থিত থাকলে আপডেট করে update

MERGE INTO Employee AS e
using EmployeeUpdate AS eu
ON e.EmployeeID = eu.EmployeeID`

@ রেমেন শেফ আমি বুঝতে পারি না। WHEN ম্যাচ করা ক্লজগুলি কোথায়?
লাইজডো

@ লাইকজুডো আমি এটি লিখিনি; আমি কেবল এটি সংশোধন করেছি। পোস্টটি লিখেছেন এমন ব্যবহারকারীকে জিজ্ঞাসা করুন।
রামেন শেফ

5

যদি কোনও আপডেট-না-সারি আপডেট করা হয় তবে তারপরে INSERT রুটটি চালানো হচ্ছে, কোনও রেসের শর্ত রোধ করার জন্য প্রথমে INSERT করার কথা বিবেচনা করুন (কোনও বিঘ্ন বিঘ্নিত হবেন না ধরে নেওয়া)

INSERT INTO MyTable (Key, FieldA)
   SELECT @Key, @FieldA
   WHERE NOT EXISTS
   (
       SELECT *
       FROM  MyTable
       WHERE Key = @Key
   )
IF @@ROWCOUNT = 0
BEGIN
   UPDATE MyTable
   SET FieldA=@FieldA
   WHERE Key=@Key
   IF @@ROWCOUNT = 0
   ... record was deleted, consider looping to re-run the INSERT, or RAISERROR ...
END

কোনও রেসের শর্ত এড়ানো ছাড়াও, যদি বেশিরভাগ ক্ষেত্রে রেকর্ডটি ইতিমধ্যে উপস্থিত থাকে তবে এটি সিপিইউ নষ্ট করে ইনসার্টকে ব্যর্থ করে দেবে।

এসকিউএল ২০০8 এর পরে সম্ভবত মার্জ ব্যবহার করা ভাল।


আকর্ষণীয় ধারণা, তবে ভুল বাক্য গঠন। SELECT এর একটি FROM <টেবিল_সোর্স> এবং একটি শীর্ষ 1 প্রয়োজন (যদি না নির্বাচিত টেবিল_সোর্সটিতে কেবল 1 সারি থাকে)।
jk7

ধন্যবাদ। আমি এটিকে একটি বিদ্যমান নেই a ও / পি অনুযায়ী "কী" এর পরীক্ষার কারণে কেবলমাত্র একটি ম্যাচিং সারি থাকবে (যদিও
ক্রাইস্টেন

4

এটি ব্যবহারের প্যাটার্নের উপর নির্ভর করে। বিশদটি হারিয়ে না গিয়ে ব্যবহারের বড় ছবিটি দেখতে হবে। উদাহরণস্বরূপ, রেকর্ডটি তৈরি হওয়ার পরে যদি ব্যবহারের প্যাটার্নটি 99% আপডেট হয় তবে 'ইউপিএসআরটি' সেরা সমাধান।

প্রথম sertোকানোর পরে (হিট), এটি সমস্ত একক বিবৃতি আপডেট হবে, কোনও আইএফ বা বুট হবে না। সন্নিবেশ করানোর ক্ষেত্রে 'যেখানে' শর্তটি প্রয়োজনীয় অন্যথায় এটি সদৃশ সন্নিবেশ করবে এবং আপনি লকিংয়ের সাথে ডিল করতে চান না।

UPDATE <tableName> SET <field>=@field WHERE key=@key;

IF @@ROWCOUNT = 0
BEGIN
   INSERT INTO <tableName> (field)
   SELECT @field
   WHERE NOT EXISTS (select * from tableName where key = @key);
END

2

এমএস এসকিউএল সার্ভার ২০০৮ মার্জ স্টেটমেন্টটি উপস্থাপন করেছে, যা আমি বিশ্বাস করি যে এসকিউএল: ২০০৩ স্ট্যান্ডার্ডের অংশ। যেহেতু অনেকে দেখিয়েছেন যে একটি সারির কেসগুলি হ্যান্ডেল করা কোনও বড় বিষয় নয়, তবে বড় ডেটাসেটগুলির সাথে কাজ করার সময় কারও কার্সার প্রয়োজন হয়, সাথে সম্পাদিত সমস্ত পারফরম্যান্স সমস্যা রয়েছে। বড় ডেটাসেটের সাথে কাজ করার সময় মার্জ স্টেটমেন্টটি অনেক স্বাগত সংযোজন করবে।


1
বড় ডেটাসেটের সাহায্যে এটি করার জন্য আমার কখনই কার্সার ব্যবহার করার দরকার নেই। আপনার কেবলমাত্র একটি আপডেট দরকার যা মেলে রেকর্ডগুলি আপডেট করে এবং সারণীতে বামিত হওয়া একটি মান মানের পরিবর্তে একটি নির্বাচন সহ সন্নিবেশ করান।
এইচএলজিইএম

1

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

স্প্রোকস সাধারণত খুব নিয়ন্ত্রিত অবস্থার অধীনে এবং একটি বিশ্বস্ত কলার (মিডিয়াল টায়ার) ধরে নিয়ে চলে। এর অর্থ হ'ল যদি কোনও সরল উপস্থাপনা প্যাটার্ন (আপডেট + সন্নিবেশ বা মার্জ) কখনও ডুপ্লিকেট পিকে দেখতে পায় যার অর্থ আপনার মাঝারি স্তর বা টেবিল ডিজাইনের একটি বাগ রয়েছে এবং এটি ভাল যে এসকিউএল এ ক্ষেত্রে একটি ত্রুটি চিৎকার করবে এবং রেকর্ডটিকে প্রত্যাখ্যান করবে। এক্ষেত্রে একটি হোল্ডলোক স্থাপন করা খাওয়ার ব্যতিক্রম এবং আপনার পারফেক্ট হ্রাস করার পাশাপাশি সম্ভাব্য ত্রুটিযুক্ত ডেটা গ্রহণের সমান।

এই বলেছিলেন যে, মার্জ ব্যবহার করুন বা আপডেট করুন তারপরে আপনার সার্ভারে INSERT সহজতর এবং কম ত্রুটিযুক্ত প্রবণতা রয়েছে কারণ আপনাকে প্রথমে নির্বাচন করার জন্য আপনাকে (UPDLOCK) যুক্ত মনে রাখতে হবে না। এছাড়াও, যদি আপনি ছোট ব্যাচে সন্নিবেশ / আপডেটগুলি করছেন তবে কোনও লেনদেন উপযুক্ত কিনা তা সিদ্ধান্ত নিতে আপনার ডেটা জানতে হবে to এটি কেবল সম্পর্কিত নয় এমন রেকর্ডের সংগ্রহ তবে অতিরিক্ত "এনভেলপিং" লেনদেন ক্ষতিকারক হবে।


1
আপনি যদি কেবল একটি আপডেট করেন তবে কোনও লকিং বা উন্নত বিচ্ছিন্নতা ছাড়াই sertোকান, তবে দুটি ব্যবহারকারী একই তথ্যটি আবার পাস করার চেষ্টা করতে পারেন (দুই ব্যবহারকারী যদি ঠিক একই তথ্য জমা দেওয়ার চেষ্টা করে তবে আমি এটি মাঝারি স্তরের একটি বাগ হিসাবে বিবেচনা করব না) একই সময় - প্রসঙ্গে অনেক কিছু নির্ভর করে, তাই না?)। তারা উভয়ই আপডেটটি প্রবেশ করে, যা উভয়ের জন্য 0 টি সারি দেয়, তারপরে তারা উভয়ই sertোকানোর চেষ্টা করে। একটি জিতে যায়, অন্যটি ব্যতিক্রম পায়। মানুষ সাধারণত এড়াতে চাইছে।
অ্যারন বার্ট্র্যান্ড 20

1

আপনি যদি প্রথমে একটি inোকানো পরে কোনও আপডেট চেষ্টা করেন তবে কি দৌড়ের পরিস্থিতি সত্যিই গুরুত্বপূর্ণ? বলুন আপনার দুটি থ্রেড রয়েছে যা কী কীটির জন্য একটি মান সেট করতে চায় :

থ্রেড 1: মান = 1
থ্রেড 2: মান = 2

উদাহরণস্বরূপ রেসের শর্তের পরিস্থিতি

  1. কী সংজ্ঞায়িত করা হয় না
  2. থ্রেড 1 আপডেটের সাথে ব্যর্থ
  3. থ্রেড 2 আপডেটের সাথে ব্যর্থ হয়
  4. ঠিক থ্রেড 1 বা থ্রেড 2 এর মধ্যে একটি সন্নিবেশ সহ সফল হয়। যেমন থ্রেড ঘ
  5. অন্যান্য থ্রেড sertোকানো ব্যর্থ হয় (ত্রুটি সদৃশ কী সহ) - থ্রেড 2।

    • ফলাফল: প্রবেশের জন্য দুটি পদক্ষেপের "প্রথম" মান স্থির করে।
    • পছন্দসই ফলাফল: ডেটা লিখতে 2 টি থ্রেডের সর্বশেষে (আপডেট বা সন্নিবেশ করা) মান নির্ধারণ করা উচিত

কিন্তু; বহুবিশ্লেষিত পরিবেশে ওএস শিডিয়ুলার থ্রেড এক্সিকিউশনের ক্রম অনুযায়ী সিদ্ধান্ত নেয় - উপরের দৃশ্যে, যেখানে আমাদের এই রেসের অবস্থা রয়েছে, এটি ওএসই ছিল যা কার্যকর করার ক্রম স্থির করে নিয়েছিল। উদাহরণস্বরূপ: "থ্রেড 1" বা "থ্রেড 2" সিস্টেমের দৃষ্টিকোণ থেকে "প্রথম" ছিল বলা ভুল।

যখন মৃত্যুদন্ডের সময়টি থ্রেড 1 এবং থ্রেড 2 এর জন্য এত কাছাকাছি থাকে, তখন রেসের শর্তের ফলাফলটি বিবেচনা করে না। একমাত্র প্রয়োজনটি হ'ল থ্রেডগুলির মধ্যে একটিতে ফলস্বরূপ মানটি সংজ্ঞায়িত করা উচিত।

বাস্তবায়নের জন্য: আপডেটের পরে যদি ত্রুটি "ডুপ্লিকেট কী" এর ফলাফল সন্নিবেশ করা হয়, তবে এটি সাফল্য হিসাবে বিবেচিত হবে।

এছাড়াও, অবশ্যই অবশ্যই কখনই ধরে নেওয়া উচিত নয় যে ডাটাবেসটিতে থাকা মানটি আপনি সর্বশেষে লিখেছেন এমন মানের সমান।


1

এসকিউএল সার্ভার ২০০৮ এ আপনি মার্জ স্টেটমেন্টটি ব্যবহার করতে পারেন


11
এটি একটি মন্তব্য। কোনও প্রকৃত উদাহরণ কোডের অভাবে এটি সাইটের অন্যান্য মতামতের মতোই।
সোয়াশেক

খুব পুরানো, তবে একটি উদাহরণ সুন্দর হবে।
ম্যাট ম্যাককেবে

0

আমি সমাধানের নীচে চেষ্টা করেছিলাম এবং এটি আমার পক্ষে কাজ করে, যখন সন্নিবেশ বিবৃতিটির জন্য একযোগে অনুরোধ আসে।

begin tran
if exists (select * from table with (updlock,serializable) where key = @key)
begin
   update table set ...
   where key = @key
end
else
begin
   insert table (key, ...)
   values (@key, ...)
end
commit tran

0

আপনি এই কোয়েরিটি ব্যবহার করতে পারেন। সমস্ত এসকিউএল সার্ভার সংস্করণে কাজ করুন। এটি সহজ এবং পরিষ্কার। তবে আপনার 2 টি প্রশ্নের প্রয়োজন। আপনি মার্জ ব্যবহার করতে না পারলে আপনি ব্যবহার করতে পারেন

    BEGIN TRAN

    UPDATE table
    SET Id = @ID, Description = @Description
    WHERE Id = @Id

    INSERT INTO table(Id, Description)
    SELECT @Id, @Description
    WHERE NOT EXISTS (SELECT NULL FROM table WHERE Id = @Id)

    COMMIT TRAN

দ্রষ্টব্য: দয়া করে উত্তর নেতিবাচক ব্যাখ্যা করুন


আমি লকিংয়ের অভাব অনুমান করছি?
Zeek2

লকিংয়ের অভাব নেই ... আমি "ট্রান" ব্যবহার করি। ডিফল্ট স্কেল-সার্ভার লেনদেনের লক রয়েছে।
ভিক্টর সানচেজ

-2

আপনি যদি ADO.NET ব্যবহার করেন তবে ডেটাএডাপ্টার এটি পরিচালনা করে।

আপনি যদি নিজে এটি পরিচালনা করতে চান তবে এই উপায়:

আপনার কী কলামে প্রাথমিক কী বাধা আছে তা নিশ্চিত করুন।

তারপরে আপনি:

  1. আপডেট করুন
  2. কীটি সহ একটি রেকর্ড ইতিমধ্যে উপস্থিত থাকার কারণে যদি আপডেট ব্যর্থ হয় তবে সন্নিবেশ করুন। আপডেট ব্যর্থ না হলে, আপনি সমাপ্ত।

আপনি এটি অন্য উপায়েও করতে পারেন, অর্থাত্ প্রথমে সন্নিবেশটি করুন এবং সন্নিবেশ ব্যর্থ হলে আপডেটটি করুন। সাধারণত প্রথম উপায়টি আরও ভাল, কারণ সন্নিবেশগুলির তুলনায় আপডেটগুলি প্রায়শই হয়।


... এবং প্রথমে সন্নিবেশ করা (এটি কখনও কখনও ব্যর্থ হবে জেনেও) এসকিউএল সার্ভারের জন্য ব্যয়বহুল। sqlperformance.com/2012/08/t-sql-queries/error-handling
অ্যারন বার্ট্র্যান্ড

-3

যদি উপস্থিত থাকে তবে একটি করা ... অন্যথায় ... ন্যূনতম দুটি অনুরোধ করা জড়িত (একটি পরীক্ষা করার জন্য, একটি পদক্ষেপ নেওয়ার জন্য)। নিম্নলিখিত পদ্ধতির জন্য কেবলমাত্র একটির প্রয়োজন যেখানে রেকর্ড বিদ্যমান, দুটি যদি একটি সন্নিবেশ প্রয়োজন হয়:

DECLARE @RowExists bit
SET @RowExists = 0
UPDATE MyTable SET DataField1 = 'xxx', @RowExists = 1 WHERE Key = 123
IF @RowExists = 0
  INSERT INTO MyTable (Key, DataField1) VALUES (123, 'xxx')

-3

আমি অন্যান্য পোস্টারগুলির মধ্যে বেশিরভাগ যা আগে উপস্থিত রয়েছে তা যাচাই করার বিষয়ে এবং তারপরে সঠিক পথটি যা করা হোক তা করার ক্ষেত্রে যা করি তা করি। এটি করার সময় আপনার একটি জিনিস মনে রাখা উচিত যে বর্গক্ষেত্র দ্বারা ক্যাশেড এক্সিকিউশন প্ল্যান একটি পাথ বা অন্যটির জন্য আপত্তিজনক হতে পারে। আমি বিশ্বাস করি এটি করার সর্বোত্তম উপায় হ'ল দুটি পৃথক সঞ্চিত প্রক্রিয়া কল করা।

FirstSP:
যদি উপস্থিত থাকে
   সেকেন্ডএসপি (আপডেটপ্রোক) কল করুন
আর
   থার্ডএসপি (ইনসার্টপ্রোক) কল করুন

এখন, আমি আমার নিজের পরামর্শটি প্রায়শই অনুসরণ করি না, তাই লবণের দানা দিয়ে এটি গ্রহণ করুন।


এটি এসকিউএল সার্ভারের প্রাচীন সংস্করণগুলিতে প্রাসঙ্গিক হতে পারে তবে আধুনিক সংস্করণগুলিতে বিবৃতি-স্তরের সংকলন রয়েছে। কাঁটাচামচ ইত্যাদি কোনও সমস্যা নয়, এবং এই বিষয়গুলির জন্য পৃথক পদ্ধতি ব্যবহার করা কোনও আপডেট এবং একটি সন্নিবেশের মধ্যে যে কোনওভাবেই চয়ন করার অন্তর্নিহিত সমস্যাগুলির কোনও সমাধান করে না ...
অ্যারন বারট্র্যান্ড

-10

একটি নির্বাচন করুন, যদি আপনি ফলাফল পান, এটি আপডেট করুন, যদি না হয় তবে এটি তৈরি করুন।


3
এটি ডাটাবেসে দুটি কল।
ক্রিস চডমোর

3
আমি তাতে কোনও সমস্যা দেখছি না।
ক্লিন্ট একার 15

10
এটি ডিবি-র দুটি কল যা সমস্যা, আপনি ডিবি-তে রাউন্ডট্রিপসের সংখ্যা দ্বিগুণ করে শেষ করবেন। যদি অ্যাপ্লিকেশন প্রচুর সন্নিবেশ / আপডেট দিয়ে ডিবিটিকে হিট করে তবে এটি কর্মক্ষমতা ক্ষতিগ্রস্থ করবে। ইউপিএসআরটি আরও ভাল কৌশল।
কেভ

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