কেন এই MERGE বিবৃতিটি অধিবেশনটিকে হত্যা করার কারণ দেখায়?


23

আমার কাছে নীচের MERGEবিবৃতিটি যা ডাটাবেসের বিরুদ্ধে জারি করা হয়েছে:

MERGE "MySchema"."Point" AS t
USING (
       SELECT "ObjectId", "PointName", z."Id" AS "LocationId", i."Id" AS "Region"
         FROM @p1 AS d
         JOIN "MySchema"."Region" AS i ON i."Name" = d."Region"
    LEFT JOIN "MySchema"."Location" AS z ON z."Name" = d."Location" AND z."Region" = i."Id"
       ) AS s
   ON s."ObjectId" = t."ObjectId"
 WHEN NOT MATCHED BY TARGET 
    THEN INSERT ("ObjectId", "Name", "LocationId", "Region") VALUES (s."ObjectId", s."PointName", s."LocationId", s."Region")
 WHEN MATCHED 
    THEN UPDATE 
     SET "Name" = s."PointName"
       , "LocationId" = s."LocationId"
       , "Region" = s."Region"
OUTPUT $action, inserted.*, deleted.*;

যাইহোক, এর ফলে নিম্নলিখিত ত্রুটির সাথে অধিবেশনটি সমাপ্ত হতে পারে:

এমএসজি 0, স্তর 11, রাজ্য 0, লাইন 67 বর্তমান কমান্ডে একটি গুরুতর ত্রুটি ঘটেছে। ফলাফল, যদি থাকে, বাতিল করা উচিত।

এমএসজি 0, স্তর 20, রাজ্য 0, লাইন 67 বর্তমান কমান্ডটিতে একটি গুরুতর ত্রুটি ঘটেছে। ফলাফল, যদি থাকে, বাতিল করা উচিত।

আমি একসঙ্গে একটি সংক্ষিপ্ত পরীক্ষার স্ক্রিপ্ট রেখেছি যা ত্রুটি তৈরি করে:

USE master;
GO
IF DB_ID('TEST') IS NOT NULL
DROP DATABASE "TEST";
GO
CREATE DATABASE "TEST";
GO
USE "TEST";
GO

SET NOCOUNT ON;

IF SCHEMA_ID('MySchema') IS NULL
EXECUTE('CREATE SCHEMA "MySchema"');
GO

IF OBJECT_ID('MySchema.Region', 'U') IS NULL
CREATE TABLE "MySchema"."Region" (
"Id" TINYINT IDENTITY NOT NULL CONSTRAINT "PK_MySchema_Region" PRIMARY KEY,
"Name" VARCHAR(8) NOT NULL CONSTRAINT "UK_MySchema_Region" UNIQUE
);
GO

INSERT [MySchema].[Region] ([Name]) 
VALUES (N'A'), (N'B'), (N'C'), (N'D'), (N'E'), ( N'F'), (N'G');

IF OBJECT_ID('MySchema.Location', 'U') IS NULL
CREATE TABLE "MySchema"."Location" (
"Id" SMALLINT IDENTITY NOT NULL CONSTRAINT "PK_MySchema_Location" PRIMARY KEY,
"Region" TINYINT NOT NULL CONSTRAINT "FK_MySchema_Location_Region" FOREIGN KEY REFERENCES "MySchema"."Region" ("Id"),
"Name" VARCHAR(128) NOT NULL,
CONSTRAINT "UK_MySchema_Location" UNIQUE ("Region", "Name") 
);
GO

IF OBJECT_ID('MySchema.Point', 'U') IS NULL
CREATE TABLE "MySchema"."Point" (
"ObjectId" BIGINT NOT NULL CONSTRAINT "PK_MySchema_Point" PRIMARY KEY,
"Name" VARCHAR(64) NOT NULL,
"LocationId" SMALLINT NULL CONSTRAINT "FK_MySchema_Point_Location" FOREIGN KEY REFERENCES "MySchema"."Location"("Id"),
"Region" TINYINT NOT NULL CONSTRAINT "FK_MySchema_Point_Region" FOREIGN KEY REFERENCES "MySchema"."Region" ("Id"),
CONSTRAINT "UK_MySchema_Point" UNIQUE ("Name", "Region", "LocationId")
);
GO

-- CONTAINS HISTORIC Point DATA
IF OBJECT_ID('MySchema.PointHistory', 'U') IS NULL
CREATE TABLE "MySchema"."PointHistory" (
"Id" BIGINT IDENTITY NOT NULL CONSTRAINT "PK_MySchema_PointHistory" PRIMARY KEY,
"ObjectId" BIGINT NOT NULL,
"Name" VARCHAR(64) NOT NULL,
"LocationId" SMALLINT NULL,
"Region" TINYINT NOT NULL
);
GO

CREATE TYPE "MySchema"."PointTable" AS TABLE (
"ObjectId"      BIGINT          NOT NULL PRIMARY KEY,
"PointName"     VARCHAR(64)     NOT NULL,
"Location"      VARCHAR(16)     NULL,
"Region"        VARCHAR(8)      NOT NULL,
UNIQUE ("PointName", "Region", "Location")
);
GO

DECLARE @p1 "MySchema"."PointTable";

insert into @p1 values(10001769996,N'ABCDEFGH',N'N/A',N'E')

MERGE "MySchema"."Point" AS t
USING (
       SELECT "ObjectId", "PointName", z."Id" AS "LocationId", i."Id" AS "Region"
         FROM @p1 AS d
         JOIN "MySchema"."Region" AS i ON i."Name" = d."Region"
    LEFT JOIN "MySchema"."Location" AS z ON z."Name" = d."Location" AND z."Region" = i."Id"
       ) AS s
   ON s."ObjectId" = t."ObjectId"
 WHEN NOT MATCHED BY TARGET 
    THEN INSERT ("ObjectId", "Name", "LocationId", "Region") VALUES (s."ObjectId", s."PointName", s."LocationId", s."Region")
 WHEN MATCHED 
    THEN UPDATE 
     SET "Name" = s."PointName"
       , "LocationId" = s."LocationId"
       , "Region" = s."Region"
OUTPUT $action, inserted.*, deleted.*;

আমি যদি OUTPUTধারাটি অপসারণ করি তবে ত্রুটিটি ঘটে না। এছাড়াও, আমি যদি deletedরেফারেন্সটি সরিয়ে ফেলি তবে ত্রুটিটি ঘটে না। সুতরাং আমি কী OUTPUTদফার জন্য এমএসডিএন নথিগুলির দিকে নজর রেখেছি :

মুছে ফেলা INSERT বিবৃতিতে OUTPUT ধারা সহ ব্যবহার করা যাবে না।

যা আমার কাছে বোধগম্য হয়, তবে পুরো বিষয়টি MERGEহ'ল আপনি আগাম জানেন না।

অতিরিক্তভাবে, নীচের স্ক্রিপ্টটি যে পদক্ষেপ নেওয়া হোক না কেন পুরোপুরি সূক্ষ্মভাবে কাজ করে:

USE tempdb;
GO
CREATE TABLE dbo.Target(EmployeeID int, EmployeeName varchar(10), 
     CONSTRAINT Target_PK PRIMARY KEY(EmployeeID));
CREATE TABLE dbo.Source(EmployeeID int, EmployeeName varchar(10), 
     CONSTRAINT Source_PK PRIMARY KEY(EmployeeID));
GO
INSERT dbo.Target(EmployeeID, EmployeeName) VALUES(100, 'Mary');
INSERT dbo.Target(EmployeeID, EmployeeName) VALUES(101, 'Sara');
INSERT dbo.Target(EmployeeID, EmployeeName) VALUES(102, 'Stefano');

GO
INSERT dbo.Source(EmployeeID, EmployeeName) Values(103, 'Bob');
INSERT dbo.Source(EmployeeID, EmployeeName) Values(104, 'Steve');
GO
-- MERGE statement with the join conditions specified correctly.
USE tempdb;
GO
BEGIN TRAN;
MERGE Target AS T
USING Source AS S
ON (T.EmployeeID = S.EmployeeID) 
WHEN NOT MATCHED BY TARGET AND S.EmployeeName LIKE 'S%' 
    THEN INSERT(EmployeeID, EmployeeName) VALUES(S.EmployeeID, S.EmployeeName)
WHEN MATCHED 
    THEN UPDATE SET T.EmployeeName = S.EmployeeName
WHEN NOT MATCHED BY SOURCE AND T.EmployeeName LIKE 'S%'
    THEN DELETE 
OUTPUT $action, inserted.*, deleted.*;
ROLLBACK TRAN;
GO 

এছাড়াও, আমার অন্যান্য প্রশ্ন রয়েছে যা OUTPUTএকই ফ্যাশনে ব্যবহার করে যা ত্রুটি ছুঁড়ে ফেলেছে এবং তারা পুরোপুরি সূক্ষ্মভাবে কাজ করে - তাদের মধ্যে কেবলমাত্র পার্থক্য হল অংশগুলি অংশ নেওয়া টেবিলগুলি MERGE

এটি আমাদের জন্য উত্পাদনে বড় সমস্যা সৃষ্টি করছে। আমি এই ত্রুটিটি এসকিউএল २०१৪ এবং এসকিউএল २०१6 এ ভিএম এবং শারীরিক উভয় ক্ষেত্রে 128 জিবি র‌্যাম, 12 এক্স 2.2 জিএইচজেড কোর, উইন্ডোজ সার্ভার 2012 আর 2 দিয়ে পুনরুত্পাদন করেছি।

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

আনুমানিক বাস্তবায়ন পরিকল্পনা


1
ক্যোয়ারী একটি আনুমানিক পরিকল্পনা তৈরি করতে পারে? (এছাড়াও, এটি প্রচুর লোককে হতবাক করবে না, তবে আমি যাইহোক যাইহোক পুরাতন আপসেট পদ্ধতিটি সুপারিশ করি - MERGEএটির HOLDLOCKজন্য আপনার কোনওটি নেই , সুতরাং এটি জাতিগত অবস্থা থেকে সুরক্ষিত নয় , এবং আরও অন্যান্য বাগগুলি এমনকি বিবেচনা করার জন্য রয়েছে আপনি সমাধান করার পরে - বা রিপোর্ট করুন - যাই হোক না কেন এই সমস্যাটি সৃষ্টি করছে))
অ্যারন বারট্র্যান্ড

1
এটি অ্যাক্সেস লঙ্ঘন সহ স্ট্যাক ডাম্প দেয়। যতদূর আমি দেখতে পাচ্ছি এখানে স্ট্যাকটি আনওয়াইন্ড করার সময় i.stack.imgur.com/f9aWa.png এটি আপনার জন্য বড় সমস্যা তৈরি করে যদি আপনার মাইক্রোসফ্ট পিএসএসের সাথে এটি উত্থাপন করা উচিত। বিশেষত মনে হচ্ছে deleted.ObjectIdএটিই সমস্যা সৃষ্টি করছে। OUTPUT $action, inserted.*, deleted.Name, deleted.LocationId, deleted.Regionঠিকভাবে কাজ করে.
মার্টিন স্মিথ

1
মার্টিনের সাথে কনকুর এর মধ্যে, MySchema.PointTableপ্রকারটি না ব্যবহার করে এবং কেবল একটি নগ্ন VALUES()ধারা, বা # টেম্প টেবিল, বা টেবিল ভেরিয়েবল ব্যবহার করে সমস্যাটি এড়াতে পারবেন কিনা তা দেখুন USING। অবদানের কারণগুলিকে আলাদা করতে সহায়তা করতে পারে।
অ্যারন বারট্র্যান্ড

আপনার সাহায্যকারী লোকদের জন্য ধন্যবাদ, আমি একটি টেম্প টেবিল ব্যবহার করার চেষ্টা করেছি এবং একই ত্রুটি ঘটেছে। আমি পণ্য সমর্থন দিয়ে এটি উত্থাপন করব - ইতিমধ্যে আমি মেশিনটি ব্যবহার না করার জন্য ক্যোয়ারীটি পুনরায় লিখেছি যাতে আমরা চলমান রাখতে পারি।
মিঃ ব্রাউনস্টোন

উত্তর:


20

এটি একটি বাগ।

এটি সম্পর্কিত MERGEস্পেসিফিক হোল-ফিলিং অপটিমাইজেশনের সাথে সম্পর্কিত যা স্পষ্টভাবে হ্যালোইন সুরক্ষা এড়ানোর জন্য এবং একটি যোগদান যোগ করতে এবং এইগুলি কীভাবে অন্যান্য আপডেট প্ল্যান বৈশিষ্ট্যগুলির সাথে ইন্টারেক্ট করে interact

আমার প্রবন্ধ, ঐ অপ্টিমাইজেশন সম্পর্কে বিস্তারিত পার্ট 3 - হ্যালোইন সমস্যা

গ্রিভওয়েটি সন্নিবেশ করা হয় এবং তার পরে একই টেবিলে মার্জ করা হয় :

পরিকল্পনা খণ্ড

সমাধান নীচে উপস্থিত

এই অপ্টিমাইজেশানকে পরাস্ত করার বিভিন্ন উপায় রয়েছে এবং তাই বাগটি এড়িয়ে চলুন।

  1. সুস্পষ্ট হ্যালোইন সুরক্ষা জোর করার জন্য একটি অননুমোদিত ট্রেস পতাকা ব্যবহার করুন:

    OPTION (QUERYTRACEON 8692);
  2. ONধারাটি এতে পরিবর্তন করুন :

    ON s."ObjectId" = t."ObjectId" + 0
  3. PointTableপ্রাথমিক কীটি এর সাথে প্রতিস্থাপন করতে টেবিলের ধরণটি পরিবর্তন করুন :

    ObjectID bigint NULL UNIQUE CLUSTERED CHECK (ObjectId IS NOT NULL)

    CHECKবাধ্যতা অংশ প্রাথমিক কী মূল নাল-প্রত্যাখ্যান সম্পত্তি সংরক্ষণে অন্তর্ভুক্ত, ঐচ্ছিক।

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

এর সাথে জানা গেছে যে বাগের দীর্ঘ লাইনে যোগ করার জন্য আরও একটি MERGE

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