আমার কাছে একটি বড় ডেটা টেবিল রয়েছে। এই সারণীতে 10 মিলিয়ন রেকর্ড রয়েছে।
এই ক্যোয়ারির জন্য সর্বোত্তম উপায় কী
Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE())
আমার কাছে একটি বড় ডেটা টেবিল রয়েছে। এই সারণীতে 10 মিলিয়ন রেকর্ড রয়েছে।
এই ক্যোয়ারির জন্য সর্বোত্তম উপায় কী
Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE())
উত্তর:
যদি আপনি সেই টেবিলের সমস্ত সারি মুছে ফেলছেন তবে সর্বাধিক সহজ বিকল্পটি হ'ল টেবিল কেটে দেওয়া, এরকম কিছু something
TRUNCATE TABLE LargeTable
GO
কাটা টেবিলটি কেবল টেবিলটি খালি করে দেবে, আপনি সারিগুলি মুছে ফেলা সীমাবদ্ধ করার জন্য WHERE ধারাটি ব্যবহার করতে পারবেন না এবং কোনও ট্রিগারকে বরখাস্ত করা হবে না।
অন্যদিকে আপনি যদি ৮০-৯০ শতাংশেরও বেশি ডেটা মুছে ফেলছেন তবে বলুন যে আপনার কাছে মোট ১১ মিলিয়ন সারি রয়েছে এবং আপনি ১০ মিলিয়ন মুছে ফেলতে চান অন্যভাবে এই 1 মিলিয়ন সারি (োকানো হবে (রেকর্ড আপনি রাখতে চান) ) অন্য মঞ্চ টেবিলে। এই বৃহত টেবিলটি কেটে নিন এবং এই 1 মিলিয়ন সারিগুলিকে সন্নিবেশ করুন।
অথবা যদি অনুমতি / দৃষ্টিভঙ্গি বা অন্যান্য অবজেক্টগুলির সাথে এই বৃহত টেবিলটি রয়েছে যার অন্তর্নিহিত টেবিলটি এই টেবিলটি ফেলে দেওয়ার ফলে প্রভাবিত না হয় তবে আপনি এই টেবিলটি সারণির তুলনায় অপেক্ষাকৃত কম পরিমাণে পেতে পারেন এবং একই স্কিমার সাথে অন্য একটি সারণী তৈরি করতে পারেন এবং এগুলি আমদানি করতে পারেন সারিগুলি এই প্রাক্তন-বৃহত টেবিলটিতে ফিরে আসে।
একটি শেষ বিকল্প যা আমি ভাবতে পারি তা হ'ল আপনার ডাটাবেসটির পরিবর্তন করা Recovery Mode to SIMPLE
এবং তারপরে কিছুটা লুপ ব্যবহার করে ছোট ব্যাচে সারিগুলি মুছুন ..
DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;
WHILE (@Deleted_Rows > 0)
BEGIN
-- Delete some small number of rows at a time
DELETE TOP (10000) LargeTable
WHERE readTime < dateadd(MONTH,-7,GETDATE())
SET @Deleted_Rows = @@ROWCOUNT;
END
এবং পুনরুদ্ধার মোডটি পুরোপুরি পরিবর্তন করতে ভুলে যাবেন না এবং আমি মনে করি এটি সম্পূর্ণরূপে অনুষঙ্গী করার জন্য আপনাকে একটি ব্যাকআপ নিতে হবে (পরিবর্তন বা পুনরুদ্ধারের পদ্ধতি)।
optimal solution for unknown case
এটাই কি স্বপ্ন না? দুর্ভাগ্যক্রমে আপনি কোনও একটি বড়ি দিয়ে প্রতিটি রোগ নিরাময় করতে পারবেন না; আমি বিভিন্ন পরিস্থিতিতে কিছু সম্ভাব্য সমাধানের পরামর্শ দিয়েছি। দুর্ভাগ্যক্রমে এখানে কোনও স্লিভার বুলেট নেই।
@ এম-আলি উত্তরটি সঠিক তবে এটিও মনে রাখবেন যে আপনি প্রতিটি অংশের পরে লেনদেন না করলে এবং একটি চেকপয়েন্ট সম্পাদন না করলে লগগুলি প্রচুর পরিমাণে বাড়তে পারে। পারফরম্যান্স টেস্ট এবং গ্রাফ সহ আমি এটি এইভাবে করব এবং এই নিবন্ধটি http://sqlperformance.com/2013/03/io-subs systemm/chunk-deletes হিসাবে উল্লেখ করব:
DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;
WHILE (@Deleted_Rows > 0)
BEGIN
BEGIN TRANSACTION
-- Delete some small number of rows at a time
DELETE TOP (10000) LargeTable
WHERE readTime < dateadd(MONTH,-7,GETDATE())
SET @Deleted_Rows = @@ROWCOUNT;
COMMIT TRANSACTION
CHECKPOINT -- for simple recovery model
END
COMMIT TRANSACTION
এবং CHECKPOINT
লগগুলি এখনও বাড়ছে। এই পরিষ্কার করার জন্য ধন্যবাদ।
@Deleted_Rows
10000 এর সাথে তুলনা করতে চাইতে পারেন বা এটি অনির্দিষ্টকালের জন্য ছোট ছোট ডেটা মুছে ফেলার কারণে আপনি একটি অসীম লুপ দিয়ে শেষ করতে পারেন। সুতরাং WHILE (@Deleted_Rows = 10000)
- যত তাড়াতাড়ি এটি মুছে ফেলার জন্য ডেটা পূর্ণ "পৃষ্ঠা" ছিল না তা বন্ধ হয়ে যাবে। আপনার বাস্তবায়নে, WHILE (@Deleted_Rows > 0)
উইন্ড-লুপটি আবার কার্যকর করবে এমনকি যদি এটি কেবল একটি সারি মুছে ফেলে, এবং পরবর্তী সম্পাদনাটি মুছে ফেলার জন্য একটি সারি বা দুটিও খুঁজে পেতে পারে - যার ফলে অসীম লুপ তৈরি হয়।
WHILE
লুপের মধ্যে তারিখ গণনা করার সাথে সাথে ক্যোয়ারীতে ব্যবহৃত তারিখটি প্রতিটি পুনরাবৃত্তির সাথে আলাদা হবে :dateadd(MONTH,-7,GETDATE())
।
WHILE
লুপের বিভিন্ন পুনরাবৃত্তির মধ্যে মুছে ফেলা হতে পারে ।
আপনি একই প্রশ্নটি কতবার কার্যকর করতে চান তা আপনি জিও + ব্যবহার করতে পারেন।
DELETE TOP (10000) [TARGETDATABASE].[SCHEMA].[TARGETTABLE]
WHERE readTime < dateadd(MONTH,-1,GETDATE());
-- how many times you want the query to repeat
GO 100
GO xx
কাজ করার কথা? আমি একটি "সঞ্চিত পদ্ধতি খুঁজে পাইনি" " ত্রুটি পেয়েছি । GO
কমান্ড ব্যতীত এটি ঠিক কাজ করে।
@ ফ্রেঞ্চিসকো গোল্ডেনস্টাইন, কেবলমাত্র একটি ছোট্ট সংশোধন। আপনার ভেরিয়েবল সেট করার পরে কমিট অবশ্যই ব্যবহার করা উচিত, অন্যথায় WHILE কেবল একবার কার্যকর করা হবে:
DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;
WHILE (@Deleted_Rows > 0)
BEGIN
BEGIN TRANSACTION
-- Delete some small number of rows at a time
DELETE TOP (10000) LargeTable
WHERE readTime < dateadd(MONTH,-7,GETDATE())
SET @Deleted_Rows = @@ROWCOUNT;
COMMIT TRANSACTION
CHECKPOINT -- for simple recovery model
END
এম.আলির এই প্রকরণটি আমার পক্ষে ভাল কাজ করছে। এটি কিছু মুছে দেয়, লগ সাফ করে এবং পুনরাবৃত্তি করে। আমি লগটি বাড়তে দেখছি, ড্রপ করে আবার শুরু করব।
DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;
WHILE (@Deleted_Rows > 0)
BEGIN
-- Delete some small number of rows at a time
delete top (100000) from InstallLog where DateTime between '2014-12-01' and '2015-02-01'
SET @Deleted_Rows = @@ROWCOUNT;
dbcc shrinkfile (MobiControlDB_log,0,truncateonly);
END
# of rows
একবারে মুছে ফেলার প্যারামিটারাইজ করতে এবং ক্লজটিও সংশোধন করেছি WHERE
। একটি যাদুমন্ত্র মত কাজ করে!
আপনি যদি পার্টিশন বাস্তবায়ন করতে ইচ্ছুক (এবং সক্ষম) হন তবে এটি সামান্য রান-টাইম ওভারহেড সহ প্রচুর পরিমাণে ডেটা অপসারণের কার্যকর কৌশল। একবারে ব্যায়ামের জন্য ব্যয়বহুল নয়, যদিও।
আমি মিনিট ব্যাপারে 21 মিলিয়ন সারির আমার টেবিল থেকে 19 মিলিয়ন সারি মুছতে সক্ষম ছিল । এই আমার পদ্ধতির।
আপনার যদি এই টেবিলটিতে একটি স্বয়ং-বর্ধিত প্রাথমিক কী থাকে তবে আপনি এই প্রাথমিক কীটি ব্যবহার করতে পারেন।
বড় সারণীর প্রাথমিক কীটির ন্যূনতম মান পান যেখানে রিডটাইম <ডেটডিড (মাস, -7, GETDATE ())। (রিডটাইমে সূচি যোগ করুন, ইতিমধ্যে উপস্থিত না থাকলে, এই সূচিটি 3 ধাপে টেবিলের সাথে যাইহোক মুছে ফেলা হবে)। এটি একটি চলক 'min_primary' এ সঞ্চয় করতে দেয়
প্রাথমিক কী> মিনি_প্রিমারিযুক্ত সমস্ত সারি একটি মঞ্চ টেবিলটিতে সন্নিবেশ করান (সারিগুলির সংখ্যা যদি বড় না হয় তবে মেমরি টেবিল)।
বড় টেবিলটি ফেলে দিন।
টেবিলটি পুনরায় তৈরি করুন। মঞ্চ টেবিল থেকে প্রধান সারণীতে সমস্ত সারি অনুলিপি করুন।
মঞ্চের টেবিলটি ফেলে দিন।
আপনি কিছুক্ষণ লুপ ব্যবহার করে ছোট ব্যাচগুলি মুছতে পারেন, এরকম কিছু:
DELETE TOP (10000) LargeTable
WHERE readTime < dateadd(MONTH,-7,GETDATE())
WHILE @@ROWCOUNT > 0
BEGIN
DELETE TOP (10000) LargeTable
WHERE readTime < dateadd(MONTH,-7,GETDATE())
END
অন্য ব্যবহার:
SET ROWCOUNT 1000 -- Buffer
DECLARE @DATE AS DATETIME = dateadd(MONTH,-7,GETDATE())
DELETE LargeTable WHERE readTime < @DATE
WHILE @@ROWCOUNT > 0
BEGIN
DELETE LargeTable WHERE readTime < @DATE
END
SET ROWCOUNT 0
ঐচ্ছিক;
লেনদেন লগ সক্ষম থাকলে, লেনদেন লগ অক্ষম করুন।
ALTER DATABASE dbname SET RECOVERY SIMPLE;
আপনি যদি এসকিউএল সার্ভার 2016 বা তার বেশি ব্যবহার করছেন এবং যদি আপনার টেবিলটিতে কলামের ভিত্তিতে পার্টিশন তৈরি করা হচ্ছে আপনি মুছে ফেলার চেষ্টা করছেন (উদাহরণস্বরূপ টাইমস্ট্যাম্প কলাম), তবে আপনি পার্টিশন দ্বারা ডেটা মুছতে এই নতুন কমান্ডটি ব্যবহার করতে পারেন।
টেবিলের সাথে কাটা (পার্টিশনগুলি ({| ... [, ... n]))
এটি কেবলমাত্র নির্বাচিত পার্টিশনগুলিতে ডেটা মুছে ফেলবে এবং টেবিলের অংশ থেকে ডেটা মুছে ফেলার সবচেয়ে কার্যকর উপায় হওয়া উচিত কারণ এটি লেনদেনের লগগুলি তৈরি করে না এবং এটি নিয়মিত কাটা কাটা হিসাবে দ্রুত করা হবে তবে সমস্ত ডেটা মোছা না করেই করা হবে টেবিল থেকে।
ত্রুটি হ'ল যদি আপনার টেবিলটি পার্টিশনের সাথে সেটআপ না করা হয়, তবে আপনাকে পুরানো স্কুলে যেতে হবে এবং নিয়মিত পদ্ধতির সাহায্যে ডেটা মুছতে হবে এবং তারপরে পার্টিশন সহ টেবিলটি পুনরায় তৈরি করতে হবে যাতে ভবিষ্যতে আপনি এটি করতে পারেন যা আমি এটি করেছি। আমি সন্নিবেশ পদ্ধতিতে বিভাজন তৈরি এবং মুছে ফেলা যুক্ত করেছি। আমার 500 মিলিয়ন সারি সহ টেবিল ছিল তাই মোছার সময় হ্রাস করার একমাত্র বিকল্প এটি ছিল।
আরও তথ্যের জন্য নীচের লিঙ্কগুলি দেখুন: https://docs.microsoft.com/en-us/sql/t-sql/statements/truncate-table-transact-sql?view=sql-server-2017
এসকিউএল সার্ভার 2016 পার্টিশন সহ টেবিল কাটা
নীচে আমি ডেটা মুছে ফেলার জন্য প্রথমে যা করেছি তা টেস্টে প্রয়োজনীয় ডেটা সহ পার্টিশনটি পুনরায় তৈরি করার আগে। ডেটা মোছা না হওয়া অবধি এই ক্যোয়ারী নির্দিষ্ট সময় উইন্ডো চলাকালীন কয়েক দিন চলবে।
:connect <<ServerName>>
use <<DatabaseName>>
SET NOCOUNT ON;
DECLARE @Deleted_Rows INT;
DECLARE @loopnum INT;
DECLARE @msg varchar(100);
DECLARE @FlagDate datetime;
SET @FlagDate = getdate() - 31;
SET @Deleted_Rows = 1;
SET @loopnum = 1;
/*while (getdate() < convert(datetime,'2018-11-08 14:00:00.000',120))
BEGIN
RAISERROR( 'WAIT for START' ,0,1) WITH NOWAIT
WAITFOR DELAY '00:10:00'
END*/
RAISERROR( 'STARTING PURGE' ,0,1) WITH NOWAIT
WHILE (1=1)
BEGIN
WHILE (@Deleted_Rows > 0 AND (datepart(hh, getdate() ) >= 12 AND datepart(hh, getdate() ) <= 20)) -- (getdate() < convert(datetime,'2018-11-08 19:00:00.000',120) )
BEGIN
-- Delete some small number of rows at a time
DELETE TOP (500000) dbo.<<table_name>>
WHERE timestamp_column < convert(datetime, @FlagDate,102)
SET @Deleted_Rows = @@ROWCOUNT;
WAITFOR DELAY '00:00:01'
select @msg = 'ROWCOUNT' + convert(varchar,@Deleted_Rows);
set @loopnum = @loopnum + 1
if @loopnum > 1000
begin
begin try
DBCC SHRINKFILE (N'<<databasename>>_log' , 0, TRUNCATEONLY)
RAISERROR( @msg ,0,1) WITH NOWAIT
end try
begin catch
RAISERROR( 'DBCC SHRINK' ,0,1) WITH NOWAIT
end catch
set @loopnum = 1
end
END
WAITFOR DELAY '00:10:00'
END
select getdate()
যদি আমি লুপ ছাড়াই বলি, আমি GOTO
স্কেল সার্ভার ব্যবহার করে প্রচুর পরিমাণে রেকর্ড মুছতে স্টেটমেন্টটি ব্যবহার করতে পারি । exa।
IsRepeat:
DELETE TOP (10000)
FROM <TableName>
IF @@ROWCOUNT > 0
GOTO IsRepeat
আপনি মুছে ফেলতে পারেন এর আকারের মতো আপনি বড় পরিমাণে ডেটা মুছতে পারেন।
আরও তথ্যের প্রয়োজন হলে আমাকে জানান।