একাধিক ভ্যালু সহ একাধিক INSERT বিবৃতি বনাম একক INSERT


119

আমি 1000 ইনসার্ট স্টেটমেন্ট ব্যবহারের মধ্যে পারফরম্যান্স তুলনা চালাচ্ছি:

INSERT INTO T_TESTS (TestId, FirstName, LastName, Age) 
   VALUES ('6f3f7257-a3d8-4a78-b2e1-c9b767cfe1c1', 'First 0', 'Last 0', 0)
INSERT INTO T_TESTS (TestId, FirstName, LastName, Age) 
   VALUES ('32023304-2e55-4768-8e52-1ba589b82c8b', 'First 1', 'Last 1', 1)
...
INSERT INTO T_TESTS (TestId, FirstName, LastName, Age) 
   VALUES ('f34d95a7-90b1-4558-be10-6ceacd53e4c4', 'First 999', 'Last 999', 999)

..ভারসাস 1000 মান সহ একক INSERT বিবৃতি ব্যবহার করে:

INSERT INTO T_TESTS (TestId, FirstName, LastName, Age) 
VALUES 
('db72b358-e9b5-4101-8d11-7d7ea3a0ae7d', 'First 0', 'Last 0', 0),
('6a4874ab-b6a3-4aa4-8ed4-a167ab21dd3d', 'First 1', 'Last 1', 1),
...
('9d7f2a58-7e57-4ed4-ba54-5e9e335fb56c', 'First 999', 'Last 999', 999)

আমার বড় আশ্চর্যের বিষয়, ফলাফলগুলি আমি যা ভেবেছিলাম তার বিপরীত:

  • 1000 INSERT বিবৃতি: 290 ম্যাসি।
  • 1000 ভ্যালু সহ 1 INSERT বিবৃতি: 2800 ম্যাসি।

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

এটি কি যুক্তিসঙ্গত হতে পারে বা কোনওভাবে ব্যাখ্যা করা যায়? কীভাবে আসুন, একটি অনুমিত দ্রুত পদ্ধতির ফলাফল 10 গুণ খারাপ ফলাফল!

ধন্যবাদ.

সম্পাদনা: উভয়ের জন্য কার্যকর করার পরিকল্পনা সংযুক্ত করা: এক্সিকিউট পরিকল্পনা


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

1
জড়িত আছে কোন ট্রিগার?
একে

2
আমি মানগুলিতে 1000 সীমা ছাড়িয়ে যাওয়ার জন্য একটি প্রোগ্রামকে টিভিটিতে রূপান্তর করেছি এবং একটি বড় পারফরম্যান্স লাভ পেয়েছি। আমি একটি তুলনা চালাতে হবে।
পাপারাজ্জো

1
প্রাসঙ্গিক: সরল-talk.com/sql/performance/…
অজানা

উত্তর:


126

সংযোজন: এসকিউএল সার্ভার 2012 এই অঞ্চলে কিছু উন্নত পারফরম্যান্স দেখায় তবে নীচে উল্লিখিত নির্দিষ্ট সমস্যাগুলি মোকাবেলা করছে বলে মনে হয় না। এটি স্পষ্টতই এসকিউএল সার্ভার ২০১২ এর পরে পরবর্তী বড় সংস্করণে স্থির করা উচিত !

আপনার পরিকল্পনাটি দেখায় যে একক সন্নিবেশকরা প্যারামিটারাইজড পদ্ধতি ব্যবহার করছে (সম্ভবত স্বয়ংক্রিয়ভাবে প্যারামিটারাইজড) তাই পার্স / সংকলনের সময়টি ন্যূনতম হওয়া উচিত।

আমি ভেবেছিলাম আমি এটিকে আরও কিছুটা অনুসন্ধান করব যদিও এইভাবে একটি লুপ ( স্ক্রিপ্ট ) সেটআপ করেছি এবং VALUESধারাগুলির সংখ্যা সামঞ্জস্য করার এবং সংকলনের সময়টি রেকর্ড করার চেষ্টা করেছি ।

তারপরে আমি ক্লোজের প্রতি গড় সংকলন সময় পাওয়ার জন্য সংকলনের সময়টিকে সারিগুলির সংখ্যা দ্বারা বিভক্ত করেছি। ফলাফলগুলি নীচে রয়েছে

চিত্রলেখ

250 টি VALUESধারা অবধি সংকলন সময় / ক্লোজের উপস্থিতি অবধি সামান্য wardর্ধ্বমুখী প্রবণতা রয়েছে তবে খুব বেশি নাটকীয় কিছুই নেই।

চিত্রলেখ

তবে তারপরে হঠাৎ পরিবর্তন ঘটে।

তথ্যের সেই অংশটি নীচে দেখানো হয়েছে।

+------+----------------+-------------+---------------+---------------+
| Rows | CachedPlanSize | CompileTime | CompileMemory | Duration/Rows |
+------+----------------+-------------+---------------+---------------+
|  245 |            528 |          41 |          2400 | 0.167346939   |
|  246 |            528 |          40 |          2416 | 0.162601626   |
|  247 |            528 |          38 |          2416 | 0.153846154   |
|  248 |            528 |          39 |          2432 | 0.157258065   |
|  249 |            528 |          39 |          2432 | 0.156626506   |
|  250 |            528 |          40 |          2448 | 0.16          |
|  251 |            400 |         273 |          3488 | 1.087649402   |
|  252 |            400 |         274 |          3496 | 1.087301587   |
|  253 |            400 |         282 |          3520 | 1.114624506   |
|  254 |            408 |         279 |          3544 | 1.098425197   |
|  255 |            408 |         290 |          3552 | 1.137254902   |
+------+----------------+-------------+---------------+---------------+

ক্যাশেড পরিকল্পনার আকার যা রৈখিকভাবে বৃদ্ধি পেয়ে হঠাৎ হ্রাস পেয়েছিল তবে কমপাইলটাইম 7 গুন এবং কমপাইল মেমোরি অঙ্কুরিত হয়। এটি অটো প্যারামিট্রাইজড (এক হাজার প্যারামিটার সহ) অ প্যারামাইট্রাইজড হওয়ার পরিকল্পনার মধ্যে কাট অফ পয়েন্ট। এরপরে এটি রৈখিকভাবে কম দক্ষ হবে বলে মনে হচ্ছে (একটি নির্দিষ্ট সময়ে প্রক্রিয়াজাতকরণের মান ধারাগুলির শর্তে)।

কেন এটি হওয়া উচিত তা নিশ্চিত নয়। সম্ভবত যখন এটি নির্দিষ্ট আক্ষরিক মানগুলির জন্য একটি পরিকল্পনা সংকলন করছে তখন অবশ্যই এমন কিছু ক্রিয়াকলাপ সম্পাদন করতে হবে যা রৈখিকভাবে স্কেল না করে (যেমন বাছাইকরণ)।

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

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

পরিকল্পনা

আমি এটি একটি ডিবাগারে দেখার চেষ্টা করেছি তবে এসকিউএল সার্ভার ২০০৮ এর আমার সংস্করণটির জন্য সর্বজনীন চিহ্নগুলি যাতে উপলব্ধ হয় না বলে মনে হয় তার পরিবর্তে আমাকে সমতুল্যটি দেখতে হবে UNION ALL এসকিউএল সার্ভার ২০০৫- নির্মাণটি দেখতে হবে।

একটি সাধারণ স্ট্যাক ট্রেস নীচে রয়েছে

sqlservr.exe!FastDBCSToUnicode()  + 0xac bytes  
sqlservr.exe!nls_sqlhilo()  + 0x35 bytes    
sqlservr.exe!CXVariant::CmpCompareStr()  + 0x2b bytes   
sqlservr.exe!CXVariantPerformCompare<167,167>::Compare()  + 0x18 bytes  
sqlservr.exe!CXVariant::CmpCompare()  + 0x11f67d bytes  
sqlservr.exe!CConstraintItvl::PcnstrItvlUnion()  + 0xe2 bytes   
sqlservr.exe!CConstraintProp::PcnstrUnion()  + 0x35e bytes  
sqlservr.exe!CLogOp_BaseSetOp::PcnstrDerive()  + 0x11a bytes    
sqlservr.exe!CLogOpArg::PcnstrDeriveHandler()  + 0x18f bytes    
sqlservr.exe!CLogOpArg::DeriveGroupProperties()  + 0xa9 bytes   
sqlservr.exe!COpArg::DeriveNormalizedGroupProperties()  + 0x40 bytes    
sqlservr.exe!COptExpr::DeriveGroupProperties()  + 0x18a bytes   
sqlservr.exe!COptExpr::DeriveGroupProperties()  + 0x146 bytes   
sqlservr.exe!COptExpr::DeriveGroupProperties()  + 0x146 bytes   
sqlservr.exe!COptExpr::DeriveGroupProperties()  + 0x146 bytes   
sqlservr.exe!CQuery::PqoBuild()  + 0x3cb bytes  
sqlservr.exe!CStmtQuery::InitQuery()  + 0x167 bytes 
sqlservr.exe!CStmtDML::InitNormal()  + 0xf0 bytes   
sqlservr.exe!CStmtDML::Init()  + 0x1b bytes 
sqlservr.exe!CCompPlan::FCompileStep()  + 0x176 bytes   
sqlservr.exe!CSQLSource::FCompile()  + 0x741 bytes  
sqlservr.exe!CSQLSource::FCompWrapper()  + 0x922be bytes    
sqlservr.exe!CSQLSource::Transform()  + 0x120431 bytes  
sqlservr.exe!CSQLSource::Compile()  + 0x2ff bytes   

স্ট্যাক ট্রেসটিতে নামগুলি বন্ধ করে স্ট্রিংয়ের সাথে তুলনা করে অনেক সময় ব্যয় করা হয় বলে মনে হয়।

এই কেবি নিবন্ধটি ইঙ্গিত দেয় যা সাধারণকরণDeriveNormalizedGroupProperties বলা হত এর সাথে সম্পর্কিত কোয়েরি প্রসেসিংয়ের স্টেজ

এই পর্যায়ে এখন বাঁধাই বা বীজগণিত বলা হয় এবং এটি পূর্ববর্তী পার্স পর্যায় থেকে পার্সে গাছের আউটপুট নেয় এবং একটি বীজবৃক্ষিত এক্সপ্রেশন ট্রি (ক্যোয়ারী প্রসেসর ট্রি) অপ্টিমাইজেশনে এগিয়ে যায় (এই ক্ষেত্রে তুচ্ছ পরিকল্পনা অপ্টিমাইজেশন) [রেফ]

আমি আরও একটি পরীক্ষা ( স্ক্রিপ্ট ) চেষ্টা করেছিলাম যা মূল পরীক্ষাটি আবার চালানো হয়েছিল তবে তিনটি ভিন্ন ভিন্ন মামলার দিকে তাকিয়ে ছিল।

  1. প্রথম নাম এবং শেষ নাম কোনও নকল ছাড়াই 10 অক্ষরের দৈর্ঘ্যের স্ট্রিং।
  2. প্রথম নাম এবং লাস্ট নেম স্ট্রিংস দৈর্ঘ্যের 50 টির নকল ছাড়াই with
  3. সমস্ত সদৃশ সহ 10 টি অক্ষরের দৈর্ঘ্যের প্রথম নাম এবং শেষ নাম স্ট্রিং।

চিত্রলেখ

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

সম্পাদন করা

এই তথ্যটি যেখানে লিভারেজ করা হয়েছে সেখানে এক জায়গায় @ লিভেন এখানে দেখিয়েছেন

SELECT * 
FROM (VALUES ('Lieven1', 1),
             ('Lieven2', 2),
             ('Lieven3', 3))Test (name, ID)
ORDER BY name, 1/ (ID - ID) 

কারণ সংকলনের সময় এটি নির্ধারণ করতে পারে যে Nameকলামটির কোনও সদৃশ নেই এটি 1/ (ID - ID)রান সময়কালে গৌণ এক্সপ্রেশন দ্বারা অর্ডার এড়িয়ে যায় (পরিকল্পনার মধ্যে কেবল একটি ORDER BYকলাম থাকে) এবং শূন্য ত্রুটির দ্বারা কোনও বিভাজন উত্থাপিত হয় না। যদি নকলগুলি টেবিলের সাথে যুক্ত করা হয় তবে সারণি অপারেটর কলাম দ্বারা দুটি ক্রম দেখায় এবং প্রত্যাশিত ত্রুটি উত্থাপিত হয়।


6
আপনার কাছে থাকা ম্যাজিক নম্বরটি নাম্বারফ্রো / কলামকন্ট = 250। এটি তালিকা <ParameterList>সহ একের সাথে একটি পরিকল্পনা তৈরি করা "সহজ" হতে পারে <ConstantScan><Values><Row>
মিকায়েল এরিকসন

1
@ মিকায়েল এরিকসন - একমত 1000 মান সহ 250 সারি একটি 251 সারিটি স্বয়ংক্রিয়ভাবে প্যারামিটারাইজড হয় যাতে পার্থক্য বলে মনে হয় না। যদিও নিশ্চিত না। সম্ভবত এটি সদৃশ মানগুলি সদৃশ করতে বা ডুপ্লিকেটগুলির সন্ধান করার জন্য সময় ব্যয় করে যখন এটি থাকে।
মার্টিন স্মিথ

1
এটি একটি দুর্দান্ত পাগল ইস্যু, আমি এটি দেখে খুব দুঃখিত হয়েছি। এটি একটি দুর্দান্ত উত্তম ধন্যবাদ
প্রিয় নয়

1
@ মিকায়েল এরিকসন আপনি কী বোঝাতে চাইছেন যে ম্যাজিক নম্বরটি নাম্বার অফরোজ * কলামকন্ট = 1000?
পাপারাজ্জো

1
@ ব্লাম - হ্যাঁ যখন উপাদানগুলির মোট সংখ্যা 1000 এরও বেশি হয় (সংখ্যাআফ্রোয় * কলামকন্ট) কোয়েরি প্ল্যানটি <ConstantScan><Values><Row>পরিবর্তে ব্যবহার করতে পরিবর্তিত হয় <ParameterList>
মিকেল এরিকসন

23

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


9

সমস্যাটি সম্ভবত ক্যোয়ারী সংকলন করতে যে সময় নেয় তার সাথে করতে হবে।

আপনি যদি সন্নিবেশগুলিকে দ্রুত করতে চান তবে আপনার যা করার দরকার তা হ'ল এগুলি একটি লেনদেনের মধ্যে আবদ্ধ করুন:

BEGIN TRAN;
INSERT INTO T_TESTS (TestId, FirstName, LastName, Age) 
   VALUES ('6f3f7257-a3d8-4a78-b2e1-c9b767cfe1c1', 'First 0', 'Last 0', 0);
INSERT INTO T_TESTS (TestId, FirstName, LastName, Age) 
   VALUES ('32023304-2e55-4768-8e52-1ba589b82c8b', 'First 1', 'Last 1', 1);
...
INSERT INTO T_TESTS (TestId, FirstName, LastName, Age) 
   VALUES ('f34d95a7-90b1-4558-be10-6ceacd53e4c4', 'First 999', 'Last 999', 999);
COMMIT TRAN;

সি # থেকে, আপনি কোনও টেবিলের মূল্যবান প্যারামিটার ব্যবহার বিবেচনা করতে পারেন। একক ব্যাচে একাধিক কমান্ড জারি করা, সেমিকোলনগুলিকে পৃথক করে, এটি অন্য পদ্ধতি যা সহায়তা করবে।


1
পুনরায়: "একক ব্যাচে একাধিক কমান্ড জারি করা": এটি কিছুটা সাহায্য করে, তবে খুব বেশি নয়। তবে আমি অবশ্যই দুটি ট্রান্সঅ্যাকশন র‌্যাপের অন্যান্য দুটি বিকল্পের সাথে একমত হই (ট্রান্স কি আসলে কাজ করে বা এটি কেবল ট্রান হওয়া উচিত?) বা টিভিপি ব্যবহারের সাথে।
সলোমন রুটজকি

1

আমি সি -++ প্রোগ্রাম (এমএফসি / ওডিবিসি) দিয়ে বেশ কয়েকটি 100 কে সারি দিয়ে একটি টেবিলকে রূপান্তর করার চেষ্টা করে একই পরিস্থিতিতে চলে এসেছি।

যেহেতু এই অপারেশনটি খুব দীর্ঘ সময় নিয়েছে, তাই আমি একের মধ্যে একাধিক সন্নিবেশ বান্ডিল করতে পেরেছি ( এমএসএসকিউএল সীমাবদ্ধতার কারণে 1000 পর্যন্ত )। আমার ধারণা যে প্রচুর একক সন্নিবেশ বিবৃতি এখানে বর্ণিত বর্ণনার অনুরূপ একটি ওভারহেড তৈরি করবে ।

তবে, দেখা যাচ্ছে যে রূপান্তরটি আসলে বেশ খানিকটা বেশি সময় নিয়েছিল:

        Method 1       Method 2     Method 3 
        Single Insert  Multi Insert Joined Inserts
Rows    1000           1000         1000
Insert  390 ms         765 ms       270 ms
per Row 0.390 ms       0.765 ms     0.27 ms

সুতরাং, সিডিটাবেজে 1000 সিঙ্গল কল :: একক ইনসার্ট স্টেটমেন্ট (পদ্ধতি 1) সহ প্রতিটি এক্সিকিউটএসকিউএল সিডিটিবেস :: এক্সিকিউটিএসকিএল-তে 1000 ভ্যালু টিপলস (পদ্ধতি 2) সহ একটি বহু-লাইন ইনসার্ট স্টেটমেন্ট সহ একক কল হিসাবে প্রায় দ্বিগুণ দ্রুত।

আপডেট: সুতরাং, পরবর্তী জিনিসটি আমি চেষ্টা করেছি হ'ল 1000 পৃথক INSERT বিবৃতিগুলিকে একক স্ট্রিংয়ে বান্ডিল করা এবং সার্ভারটিকে (পদ্ধতি 3) সম্পাদন করা উচিত। দেখা যাচ্ছে এটি পদ্ধতি 1 এর চেয়ে কিছুটা দ্রুত।

সম্পাদনা করুন: আমি মাইক্রোসফ্ট এসকিউএল সার্ভার এক্সপ্রেস সংস্করণ (64-বিট) ভি 10.0.2531.0 ব্যবহার করছি

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