ক্লাস্টারড ইনডেক্স সহ একটি সারণিতে দক্ষ ইনসার্ট IN


28

আমার একটি এসকিউএল বিবৃতি রয়েছে যা TRACKING_NUMBER কলামে একটি ক্লাস্টার্ড সূচক সহ একটি সারণীতে সারি সন্নিবেশ করিয়েছে।

উদাহরণ:

INSERT INTO TABL_NAME (TRACKING_NUMBER, COLB, COLC) 
SELECT TRACKING_NUMBER, COL_B, COL_C 
FROM STAGING_TABLE

আমার প্রশ্নটি হ'ল - এটি কি ক্লাস্টারড ইনডেক্স কলামের জন্য SELECT স্টেটমেন্টে অর্ডার বাই ধারাটি ব্যবহার করতে সহায়তা করে, বা অর্ডারের দ্বারা প্রয়োজনীয় অতিরিক্ত সাজানোর দ্বারা প্রাপ্ত কোনও লাভকে উপেক্ষা করা হবে?

উত্তর:


18

অন্য উত্তরগুলির মধ্যে ইতিমধ্যে এসকিউএল সার্ভারটি ইঙ্গিত দিচ্ছে যে স্পষ্টভাবে নিশ্চিত করতে পারে যে সারিগুলি ক্লাস্টারড সূচী ক্রমে সাজানো হয়েছে এর আগে insert

পরিকল্পনার ক্লাস্টারড ইনডেক্স অপারেটরের DMLRequestSortসম্পত্তি সেট রয়েছে কিনা তার উপর এটি নির্ভরশীল (যা সন্নিবেশ করা সারিগুলির আনুমানিক সংখ্যার উপর নির্ভর করে)।

আপনি যদি দেখতে পান যে এসকিউএল সার্ভার কোনও কারণেই পেজ বিভাজন হ্রাস করতে এবং ক্রিয়াকলাপ থেকে খণ্ডিত অংশটি ভাঙ্গার ORDER BYজন্য SELECTক্যোয়ারিতে একটি স্পষ্ট যোগ করে আপনি উপকৃত হতে পারেন তবে এটি এটিকে অবমূল্যায়ন INSERTকরছে

উদাহরণ:

use tempdb;

GO

CREATE TABLE T(N INT PRIMARY KEY,Filler char(2000))

CREATE TABLE T2(N INT PRIMARY KEY,Filler char(2000))

GO

DECLARE @T TABLE (U UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),N int)

INSERT INTO @T(N)
SELECT number 
FROM master..spt_values
WHERE type = 'P' AND number BETWEEN 0 AND 499

/*Estimated row count wrong as inserting from table variable*/
INSERT INTO T(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2

/*Same operation using explicit sort*/    
INSERT INTO T2(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
ORDER BY T1.N*1000 + T2.N


SELECT avg_fragmentation_in_percent,
       fragment_count,
       page_count,
       avg_page_space_used_in_percent,
       record_count
FROM   sys.dm_db_index_physical_stats(2, OBJECT_ID('T'), NULL, NULL, 'DETAILED')
;  


SELECT avg_fragmentation_in_percent,
       fragment_count,
       page_count,
       avg_page_space_used_in_percent,
       record_count
FROM   sys.dm_db_index_physical_stats(2, OBJECT_ID('T2'), NULL, NULL, 'DETAILED')
;  

যেগুলি Tব্যাপকভাবে খণ্ডিত হয় ows

avg_fragmentation_in_percent fragment_count       page_count           avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
99.3116118225536             92535                92535                67.1668272794663               250000
99.5                         200                  200                  74.2868173956017               92535
0                            1                    1                    32.0978502594514               200

কিন্তু T2খণ্ডের জন্য ন্যূনতম

avg_fragmentation_in_percent fragment_count       page_count           avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
0.376                        262                  62500                99.456387447492                250000
2.1551724137931              232                  232                  43.2438349394613               62500
0                            1                    1                    37.2374598468001               232

বিপরীত সময়ে কখনও কখনও আপনি এসকিউএল সার্ভারকে সারণী গণনাটি অবমূল্যায়ন করতে বাধ্য করতে পারেন যখন আপনি জানেন যে ডেটা ইতোমধ্যে প্রাক-বাছাই করা হয়েছে এবং অপ্রয়োজনীয় বাছাই করা এড়াতে চান। একটি উল্লেখযোগ্য উদাহরণ হ'ল একটি newsequentialidক্লাস্টারড ইনডেক্স কী সহ একটি বড় সংখ্যক সারি একটি টেবিলের মধ্যে সন্নিবেশ করানোর সময় । SQL সার্ভার এর সংস্করণে Denali SQL সার্ভার পূর্বে একটি অপ্রয়োজনীয় এবং সম্ভাব্য ব্যয়বহুল সাজানোর অপারেশন যোগ । এটি এড়ানো যায়

DECLARE @var INT =2147483647

INSERT INTO Foo
SELECT TOP (@var) *
FROM Bar

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



12

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

আপনি যদি সুস্পষ্ট বাছাইয়ের সাথে বা ছাড়া প্রক্রিয়াটির বাস্তবায়ন পরিকল্পনাগুলি ক্যাপচার করতে পারেন তবে তাদের প্রশ্নের জন্য আপনার মন্তব্যে সংযুক্ত করুন।

সম্পাদনা করুন: 2011-10-28 17:00

@ গনসালুর উত্তরে দেখা যাচ্ছে যে কোনও ধরণের ক্রিয়াকলাপ সর্বদা ঘটে থাকে, এটি এমন নয়। ডেমো স্ক্রিপ্ট প্রয়োজন!

স্ক্রিপ্টগুলি বেশ বড় হয়ে যাওয়ায় , আমি এগুলিকে গিস্টে স্থানান্তরিত করেছি । পরীক্ষার স্বাচ্ছন্দ্যের জন্য, স্ক্রিপ্টগুলি এসকিউএলসিএমডি মোড ব্যবহার করে। টেস্টগুলি 2K5SP3, ডুয়াল কোর, 8 জিবিতে চলে।

সন্নিবেশ পরীক্ষায় তিনটি পরিস্থিতি রয়েছে:

  1. লক্ষ্য হিসাবে একই ক্রমে ডেটা ক্লাস্টারড সূচক মঞ্চায়ন।
  2. বিপরীত ক্রমে ডেটা ক্লাস্টারড ইনডেক্স মঞ্চায়ন।
  3. কোল 2 দ্বারা ক্লাস্টার করা ডেটা মঞ্চে র্যান্ডম আইএনটি থাকে IN

প্রথমে চালান, 25 টি সারি .োকানো।

1 ম রান, 25 সারি

তিনটি কার্যকর করার পরিকল্পনা একই, পরিকল্পনার কোথাও কোনও সাজানো হয় না এবং ক্লাস্টারড ইনডেক্স স্ক্যানটি "অর্ডারড = মিথ্যা" হয়।

দ্বিতীয় রান, 26 টি সারি .োকানো।

২ য় রান, ২ r টি সারি

এবারও পরিকল্পনা আলাদা।

  • প্রথমে ক্লাস্টারড ইনডেক্স স্ক্যানটি অর্ডার = মিথ্যা হিসাবে দেখায়। উত্স ডেটা যথাযথভাবে বাছাই করা হওয়ায় কোনও ধরণের ঘটনা ঘটেনি।
  • দ্বিতীয়টিতে ক্লাস্টারড ইনডেক্স স্ক্যান অর্ডার = সত্য, পিছনে হিসাবে। সুতরাং আমাদের একটি বাছাই অপারেশন নেই তবে ডেটা বাছাইয়ের প্রয়োজনীয়তাটি অপটিমাইজারের দ্বারা স্বীকৃত এবং এটি বিপরীত ক্রমে স্ক্যান করে।
  • তৃতীয়টি একটি সাজানো অপারেটর দেখায়।

সুতরাং, একটি টিপিং পয়েন্ট রয়েছে যেখানে অপটিমাইজার একটি ধরণের প্রয়োজন মনে করে। @ মার্টিনস্মিথ দেখায়, এটি theোকানো আনুমানিক সারিগুলির উপর ভিত্তি করে প্রদর্শিত হবে। আমার পরীক্ষার জন্য 25 টি ধরণের প্রয়োজন নেই, 26 টি (2 কে 5 এসপি 3, ডুয়াল কোর, 8 জিবি)

এসকিউএলসিএমডি স্ক্রিপ্টে এমন ভেরিয়েবলগুলি অন্তর্ভুক্ত রয়েছে যা টেবিলের সারিগুলির আকার পরিবর্তন করতে দেয় (পৃষ্ঠার ঘনত্ব পরিবর্তন করে) এবং অতিরিক্ত সন্নিবেশের আগে dbo.MyTable এ সারিগুলির সংখ্যা পরিবর্তন করতে দেয়। আমার পরীক্ষা থেকে, টিপিং পয়েন্টে কোনওটিরই প্রভাব নেই।

কোনও পাঠক যদি এতো ঝোঁক থাকে তবে দয়া করে স্ক্রিপ্টগুলি চালনা করুন এবং একটি মন্তব্য হিসাবে আপনার টিপিং পয়েন্ট যুক্ত করুন। এটি টেস্ট রিগ এবং / অথবা সংস্করণগুলিতে পরিবর্তিত হয় তা শুনতে আগ্রহী।

সম্পাদনা করুন: 2011-10-28 20:15

একই কান্ডে কিন্তু 2K8R2 দিয়ে পুনরাবৃত্তি পরীক্ষা। এবার টিপিং পয়েন্টটি 251 টি সারি। আবার, পৃষ্ঠা ঘনত্ব এবং বিদ্যমান সারি গণনার পরিবর্তিত করার কোনও প্রভাব নেই।


8

ORDER BYমধ্যে দফা SELECTবিবৃতি অপ্রয়োজনীয়।

এটি অনর্থক কারণ যে সারিগুলি সন্নিবেশ করা হবে, যদি তাদের বাছাই করা দরকার হয় তবে যেভাবেই তা বাছাই করা হয়।

আসুন একটি পরীক্ষা কেস তৈরি করুন।

CREATE TABLE #Test (
    id INTEGER NOT NULL
);

CREATE UNIQUE CLUSTERED INDEX CL_Test_ID ON #Test (id);

CREATE TABLE #Sequence (
    number INTEGER NOT NULL
);

INSERT INTO #Sequence
SELECT number FROM master..spt_values WHERE name IS NULL;

আসুন আসল ক্যোয়ারী পরিকল্পনাগুলির পাঠ্য প্রদর্শন সক্ষম করুন, যাতে আমরা দেখতে পারি যে কোয়েরি প্রসেসর দ্বারা কোন কাজ সম্পাদিত হয়।

SET STATISTICS PROFILE ON;
GO

এখন, INSERTকোনও ORDER BYধারা ছাড়াই টেবিলের 2K সারিগুলিতে আসুন ।

INSERT INTO #Test
SELECT number
  FROM #Sequence

এই ক্যোয়ারির জন্য প্রকৃত বাস্তবায়ন পরিকল্পনাটি নিম্নলিখিত।

INSERT INTO #Test  SELECT number    FROM #Sequence
  |--Clustered Index Insert(OBJECT:([tempdb].[dbo].[#Test]), SET:([tempdb].[dbo].[#Test].[id] = [tempdb].[dbo].[#Sequence].[number]))
       |--Top(ROWCOUNT est 0)
            |--Sort(ORDER BY:([tempdb].[dbo].[#Sequence].[number] ASC))
                 |--Table Scan(OBJECT:([tempdb].[dbo].[#Sequence]))

আপনি দেখতে পাচ্ছেন, আসল INSERT হওয়ার আগে একটি সোর্ট অপারেটর রয়েছে।

এখন, টেবিল ও পরিষ্কার দিন INSERTটেবিল মধ্যে 2k সারি ORDER BYদফা।

TRUNCATE TABLE #Test;
GO

INSERT INTO #Test
SELECT number
  FROM #Sequence
 ORDER BY number

এই ক্যোয়ারির জন্য প্রকৃত বাস্তবায়ন পরিকল্পনাটি নিম্নলিখিত।

INSERT INTO #Test  SELECT number    FROM #Sequence   ORDER BY number
  |--Clustered Index Insert(OBJECT:([tempdb].[dbo].[#Test]), SET:([tempdb].[dbo].[#Test].[id] = [tempdb].[dbo].[#Sequence].[number]))
       |--Top(ROWCOUNT est 0)
            |--Sort(ORDER BY:([tempdb].[dbo].[#Sequence].[number] ASC))
                 |--Table Scan(OBJECT:([tempdb].[dbo].[#Sequence]))

নোট করুন যে এটি একই কার্যকরকরণ পরিকল্পনা যা দফা INSERTব্যতীত বিবৃতিতে ব্যবহার করা হয়েছিল ORDER BY

এখন, Sortঅপারেশনটি সবসময় প্রয়োজন হয় না, যেমন মার্ক স্মিথ অন্য উত্তরে দেখিয়েছেন (সন্নিবেশ করার জন্য সারিগুলির সংখ্যা কম থাকলে), তবে সেক্ষেত্রে ORDER BYধারাটি অপ্রয়োজনীয়, কারণ এমনকি স্পষ্টতই ORDER BY, কোনও Sortঅপারেশন তৈরি করা হয়নি ক্যোয়ারী প্রসেসর দ্বারা।

আপনি INSERTএকটি ক্লাস্টার ইনডেক্স সহ একটি টেবিলের মধ্যে একটি বিবৃতি অপেক্ষাকৃত কম-লগড ব্যবহার করে অনুকূল করতে পারেন INSERT, তবে এটি এই প্রশ্নের সুযোগের বাইরে।

আপডেট করা হয়েছে ২০১১-১১-০২: মার্ক স্মিথ যেমন দেখিয়েছেন , INSERTক্লাস্টারড ইনডেক্সের একটি টেবিলের মধ্যে সবসময় সাজানোর দরকার পড়তে পারে না - ORDER BYযদিও এই ক্ষেত্রে দফাটিও অপ্রয়োজনীয়।

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