এনভিচারচার (৪০০০) থেকে এনভিচারচার (260) -তে দ্রুত পরিবর্তন করুন কলাম


12

আমার বেশ কয়েকটি বড় মেমরি অনুদানের সাথে এই টেবিলটি কয়েক NVARCHAR(4000)কলাম সহ পরিচালনা করছে problem কথাটি হচ্ছে এই কলামগুলি এর চেয়ে বড় কখনও নয় NVARCHAR(260)

ব্যবহার

ALTER TABLE [table] ALTER COLUMN [col] NVARCHAR(260) NULL

এসকিউএল সার্ভারের ফলাফলটি পুরো টেবিলটি পুনরায় লেখার জন্য (এবং লগ স্পেসে 2x টেবিলের আকার ব্যবহার করে) যা কয়েক বিলিয়ন সারি, কেবল কিছুই পরিবর্তন করার জন্য, কোনও বিকল্প নয়। কলামের প্রস্থ বৃদ্ধিতে এই সমস্যা নেই, তবে এটি হ্রাস পেয়েছে।

আমি একটি সীমাবদ্ধতা তৈরি করার চেষ্টা করেছি CHECK (DATALENGTH([col]) <= 520)বা CHECK (LEN([col]) <= 260)এসকিউএল সার্ভার এখনও পুরো টেবিলটি পুনরায় লেখার সিদ্ধান্ত নিয়েছে।

কেবলমাত্র মেটাডেটা অপারেশন হিসাবে কলামের ডেটা ধরণের পরিবর্তন করার কোনও উপায় আছে? পুরো টেবিলটি আবার লেখার ব্যয় ছাড়াই? আমি এসকিউএল সার্ভার 2017 (14.0.2027.2 এবং 14.0.3192.2) ব্যবহার করছি।

পুনরুত্পাদন করার জন্য এখানে একটি নমুনা ডিডিএল টেবিল রয়েছে:

CREATE TABLE [table](
    id INT IDENTITY(1,1) NOT NULL,
    [col] NVARCHAR(4000) NULL,
    CONSTRAINT [PK_test] PRIMARY KEY CLUSTERED (id ASC)
);

এবং তারপর চালান ALTER

উত্তর:


16

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

  1. এটি যে সমস্ত কোড ব্যবহার করে সেগুলিতে কলামটি এনভিচারচার (260) হিসাবে কাস্ট করুন। ক্যোয়ারী অপ্টিমাইজার কাঁচা ডেটার পরিবর্তে কাস্ট করা ডেটা টাইপ ব্যবহার করে মেমরি অনুদান গণনা করবে।
  2. টেবিলটির নতুন নাম দিন এবং এমন দৃশ্য তৈরি করুন যা পরিবর্তে কাস্ট করে does এটি বিকল্প 1 হিসাবে একই জিনিসটি সম্পাদন করে তবে আপনাকে আপডেট করার মতো কোডের পরিমাণ সীমাবদ্ধ করতে পারে।
  3. সঠিক তথ্য প্রকারের সাথে একটি অ-স্থিত গণিত কলাম তৈরি করুন এবং আপনার সমস্ত প্রশ্নের মূল কলামের পরিবর্তে সেই কলামটি থেকে নির্বাচন করুন।
  4. বিদ্যমান কলামটির নাম পরিবর্তন করুন এবং আসল নামের সাথে গণিত কলাম যুক্ত করুন। তারপরে পরিবর্তে নতুন কলামের নাম ব্যবহার করতে আপনার সমস্ত ক্যোরিয়াকে আপডেট করে বা মূল কলামটিতে সন্নিবেশ করানো সামঞ্জস্য করুন।

15

কেবলমাত্র মেটাডেটা অপারেশন হিসাবে কলামের ডেটা ধরণের পরিবর্তন করার কোনও উপায় আছে?

আমার মনে হয় না, এখনই পণ্যটি এভাবে কাজ করে। জো এর উত্তরে প্রস্তাবিত এই সীমাবদ্ধতার জন্য কিছু সত্যই দুর্দান্ত কাজ রয়েছে ।

... এসকিউএল সার্ভারের ফলাফলটি পুরো টেবিলটি পুনরায় লিখন করে (এবং লগ স্পেসে 2x টেবিল আকার ব্যবহার করে)

আমি এই বিবৃতি দুটি অংশ পৃথকভাবে প্রতিক্রিয়া করতে যাচ্ছি।

সারণীটি পুনরায় লেখা হচ্ছে

যেমনটি আমি আগেই বলেছি, এটি এড়াতে আসলেই কোনও উপায় নেই। এটি পরিস্থিতির বাস্তবতা বলে মনে হচ্ছে, যদিও এটি গ্রাহক হিসাবে আমাদের দৃষ্টিকোণ থেকে সম্পূর্ণ উপলব্ধি করে না।

এ খুঁজছি DBCC PAGEআগে ও 4000 260 দেখায় যে তথ্য সমস্ত ডেটা পৃষ্ঠাতে সদৃশ থেকে কলাম পরিবর্তন করার পর (আমার পরীক্ষা টেবিল ছিল 'A'সারিতে 260 বার):

এর আগে ও পরে ডিবিসিসি পৃষ্ঠার ডেটা অংশের স্ক্রিনশট

এই মুহুর্তে, পৃষ্ঠায় সঠিক একই তথ্যের দুটি অনুলিপি রয়েছে। "পুরানো" কলামটি মূলত মুছে ফেলা হয়েছে (আইডিটি আইডি = 2 থেকে আইডি = 67108865 এ পরিবর্তিত হয়েছে), এবং কলামটির "নতুন" সংস্করণটি পৃষ্ঠায় ডেটার নতুন অফসেটের দিকে নির্দেশ করতে আপডেট করা হয়েছে:

এর আগে এবং পরে ডিবিসিসি পৃষ্ঠার কলাম মেটাডেটার অংশগুলির স্ক্রিনশট

লগ স্পেসে 2x সারণী আকার ব্যবহার করা

বিবৃতিটির WITH (ONLINE = ON)শেষে যুক্ত করা লগিং ক্রিয়াকলাপকে প্রায় অর্ধেক দ্বারা হ্রাস করে , তাই ডিস্ক / ডিস্কের জন্য প্রয়োজনীয় জায়গাগুলিতে লেখার পরিমাণ হ্রাস করতে আপনি এটি করতে পারেন improvementALTER

আমি এই পরীক্ষার জোতা ব্যবহার করে দেখতে চেষ্টা করেছি:

USE [master];
GO
DROP DATABASE IF EXISTS [248749];
GO
CREATE DATABASE [248749] 
ON PRIMARY 
(
    NAME = N'248749', 
    FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\DATA\248749.mdf', 
    SIZE = 2048000KB, 
    FILEGROWTH = 65536KB
)
LOG ON 
(
    NAME = N'248749_log', 
    FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\DATA\248749_log.ldf', 
    SIZE = 2048000KB, 
    FILEGROWTH = 65536KB
);
GO
USE [248749];
GO

CREATE TABLE dbo.[table]
(
    id int IDENTITY(1,1) NOT NULL,
    [col] nvarchar (4000) NULL,

    CONSTRAINT [PK_test] PRIMARY KEY CLUSTERED (id ASC)
);

INSERT INTO dbo.[table]
SELECT TOP (1000000)
    REPLICATE(N'A', 260)
FROM master.dbo.spt_values v1
    CROSS JOIN master.dbo.spt_values v2
    CROSS JOIN master.dbo.spt_values v3;
GO

আমি বিবৃতি sys.dm_io_virtual_file_stats(DB_ID(N'248749'), DEFAULT)চালানোর আগে এবং পরে পরীক্ষা করেছি ALTERএবং এখানে পার্থক্যগুলি রয়েছে:

ডিফল্ট (অফলাইন) ALTER

  • ডেটা ফাইল লিখিত / বাইট লিখিত: 34,809 / 2,193,801,216
  • লগ ফাইল লিখে / বাইট লিখিত: 40,953 / 1,484,910,080

অনলাইন ALTER

  • ডেটা ফাইল লিখে / বাইট লিখেছেন: 36,874 / 1,693,745,152 (22.8% ড্রপ)
  • লগ ফাইলটি লিখে / বাইট লিখেছেন: 24,680 / 866,166,272 (41% ড্রপ)

আপনি দেখতে পাচ্ছেন যে ডেটা ফাইলের লেখায় কিছুটা ড্রপ ছিল এবং লগ ফাইলের মধ্যে একটি বড় ড্রপ লিখেছে।


2

আমি অনেক সময় একই পরিস্থিতিতে ছিলাম।

পদক্ষেপ:

পছন্দসই প্রস্থের একটি নতুন করল যুক্ত করুন

পুরানো কলাম থেকে নতুন কলামে ডেটা অনুলিপি করতে প্রতিশ্রুতি প্রতি কয়েক হাজার পুনরাবৃত্তি (সম্ভবত দশ বা বিশ হাজার) সহ একটি কার্সার ব্যবহার করুন

পুরানো কলামটি ফেলে দিন

পুরানো কলামের নামে নতুন কলামটির নামকরণ করুন

Tada!


3
যদি আপনি ইতিমধ্যে অনুলিপি করা কিছু রেকর্ড আপডেট হয়ে থাকে, বা মুছে ফেলা হয় তবে কী হবে?
জর্জ.পালাসিয়োস

1
update table set new_col = old_col where new_col <> old_col;নামার আগে একটি ফাইনাল করা খুব সহজ old_col
কলিন 'হার্ট

1
@ কলিন্টহার্ট এই পন্থাটি কয়েক মিলিয়ন সারি দিয়ে কাজ করবে না ... লেনদেনটি বিশাল
আকার ধারণ করে

@ স্যামস্মিথ প্রথমে আপনি উপরে বর্ণিত যা করেন তা করুন। তারপরে, মূল কলামটি বাদ দেওয়ার আগে, যদি এর মধ্যে মূল ডেটাতে কোনও আপডেট থাকে তবে সেই আপডেটের স্টেটমেন্টটি চালান। এটি শুধুমাত্র কয়েকটি সারি পরিবর্তিত হয়েছে affect নাকি আমি কিছু মিস করছি?
কলিন 'হার্ট

প্রক্রিয়া চলাকালীন আপডেট হওয়া সারিগুলি কভার করার জন্য, সম্পূর্ণ স্ক্যানটি এড়িয়ে যাওয়ার চেষ্টা করা হচ্ছে যে where new_col <> old_colঅন্য কোনও ফিল্টারিং শুল্কের ফলস্বরূপ ফল না পেয়ে আপনি এই পরিবর্তনগুলি ঘটে যাওয়ার সাথে সাথে চালিয়ে যাওয়ার জন্য ট্রিগার যুক্ত করতে পারেন এবং প্রক্রিয়াটির শেষে এটি সরিয়ে ফেলতে পারেন। এখনও একটি সম্ভাব্য পারফরম্যান্স হিট, তবে প্রক্রিয়াটির দৈর্ঘ্যের উপরে অনেক ছোট পরিমাণের পরিবর্তে এক বিশাল হিটের পরিবর্তে সম্ভবত (টেবিলের জন্য আপনার অ্যাপ্লিকেশনটির আপডেট প্যাটার্নের উপর নির্ভর করে) এক বিশাল হিটের তুলনায় মোট তুলনায় অনেক কম ।
ডেভিড স্পিলিট

1

ঠিক আছে আপনার ডাটাবেসে উপলব্ধ স্থানের উপর নির্ভর করে বিকল্প রয়েছে।

  1. আপনার টেবিল (যেমন এর একটি সঠিক অনুলিপি তৈরি করুন new_table), কলাম তুমি কোথা থেকে সংক্ষেপিত করা হবে না করা ছাড়া তাদের NVARCHAR(4000)কাছে NVARCHAR(260):

    CREATE TABLE [new_table](
        id INT IDENTITY(1,1) NOT NULL,
        [col] NVARCHAR(260) NULL,
        CONSTRAINT [PK_test_new] PRIMARY KEY CLUSTERED (id ASC)
    );
    
  2. একটি রক্ষণাবেক্ষণ উইন্ডোতে "ভাঙ্গা" টেবিল ( table) থেকে "স্থির" টেবিলটিতে ( new_table) একটি সাধারণ সহ অনুলিপি করুন INSERT ... INTO ... SELECT ....:

    SET IDENTITY_INSERT [new_table] ON
    GO
    INSERT id, col INTO [new_table] SELECT id, col from [table]
    GO
    SET IDENTITY_INSERT [new_table] OFF
    GO
    
  3. "ভাঙা" টেবিলটির tableঅন্য কোনও নামকরণ করুন :

    EXEC sp_rename 'table', 'old_table';  
  4. "Fixed" টেবিল পুনঃনামকরণ new_tableকরা table:

    EXEC sp_rename 'new_table', 'table';  
  5. যদি সবকিছু ঠিক থাকে তবে "ভাঙ্গা" নাম পরিবর্তিত টেবিলটি ফেলে দিন:

     DROP TABLE [old_table]
     GO
    

এই নাও.

আপনার প্রশ্নের উত্তর

কেবলমাত্র মেটাডেটা অপারেশন হিসাবে কলামের ডেটা ধরণের পরিবর্তন করার কোনও উপায় আছে?

না। বর্তমানে সম্ভব নয়

পুরো টেবিলটি আবার লেখার ব্যয় ছাড়াই?

নং
( আমার সমাধান এবং অন্যান্যগুলি দেখুন ))


আপনার "নির্বাচিত থেকে সন্নিবেশ" এর ফলস্বরূপ, একটি বড় টেবিলের (মিলিয়ন বা বিলিয়ন কোটি সারি) অনন্য লেনদেনের ফলে, দশক বা কয়েকশত মিনিটের জন্য ডিবিটিকে থামতে পারে। (পাশাপাশি এলডিএফকে প্রচুর এবং সম্ভবত ভাঙার লগ শিপিং তৈরি করার পাশাপাশি যদি ব্যবহার হয়)
জোনসোম পুনরায় ইনস্টল করুন মনিকা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.