জোর প্রবাহ জোর করা


19

আমার এই মত একটি টেবিল আছে:

CREATE TABLE Updates
(
    UpdateId INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
    ObjectId INT NOT NULL
)

মূলত বর্ধমান আইডি সহ অবজেক্টগুলিতে আপডেটগুলি ট্র্যাক করা।

এই টেবিলের গ্রাহক ১০০ স্বতন্ত্র অবজেক্ট আইডির একটি অংশ বেছে নেবেন, অর্ডার দিয়ে UpdateIdএবং নির্দিষ্ট থেকে শুরু করে UpdateId। মূলত, এটি কোথায় ছেড়ে গেছে তা ট্র্যাক করে রাখা এবং তারপরে কোনও আপডেটের জন্য অনুসন্ধান করা।

আমি এটি একটি আকর্ষণীয় অপ্টিমাইজেশান সমস্যা হিসাবে পেয়েছি কারণ আমি কেবলমাত্র সন্ধানের সূত্রগুলির কারণে যা করতে চাই তা ঘটায় এমন প্রশ্নগুলি লিখে সর্বাধিক অনুকূল কোয়েরি পরিকল্পনা তৈরি করতে সক্ষম হয়েছি তবে আমি কী চাই তা গ্যারান্টি দিচ্ছি না:

SELECT DISTINCT TOP 100 ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId

যেখানে @fromUpdateIdএকটি সঞ্চিত প্রক্রিয়া পরামিতি।

এর একটি পরিকল্পনা সহ:

SELECT <- TOP <- Hash match (flow distinct, 100 rows touched) <- Index seek

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

এই কৌশলটি একই ক্যোয়ারী পরিকল্পনার ফলাফলও দেয় (যদিও অপ্রয়োজনীয় শীর্ষের সাথে):

WITH ids AS
(
    SELECT ObjectId
    FROM Updates
    WHERE UpdateId > @fromUpdateId
    ORDER BY UpdateId OFFSET 0 ROWS
)
SELECT DISTINCT TOP 100 ObjectId FROM ids

যদিও, আমি নিশ্চিত নই (এবং সন্দেহ নেই) যদি এটি সত্যই অর্ডার দেওয়ার নিশ্চয়তা দেয়।

আমি আশা করি যে এসকিউএল সার্ভারটি সহজ করার জন্য যথেষ্ট স্মার্ট হবে এটি একটি কোয়েরি, তবে এটি একটি খুব খারাপ ক্যোয়ারী পরিকল্পনা উত্পন্ন করে:

SELECT TOP 100 ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
GROUP BY ObjectId
ORDER BY MIN(UpdateId)

এর একটি পরিকল্পনা সহ:

SELECT <- Top N Sort <- Hash Match aggregate (50,000+ rows touched) <- Index Seek

আমি একটি সূচী অনুসারে একটি অনুকূল পরিকল্পনা উত্পন্ন করার একটি উপায় UpdateIdএবং সদৃশগুলি অপসারণের জন্য পৃথক একটি প্রবাহের সন্ধান করার চেষ্টা করছি ObjectId। কোন ধারনা?

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

ব্যবহারকারী ধরে এই পরবর্তী উপযুক্ত এটি অন্য উপায় আছে @fromUpdateId। এই কোয়েরিতে এটি ফেরত দেওয়ার দরকার নেই।

উত্তর:


15

এসকিউএল সার্ভার অপ্টিমাইজার আপনার প্রয়োজনীয় গ্যারান্টিটি সহ আপনি যে এক্সিকিউশন প্ল্যানটি তৈরি করতে পারবেন তা হ্যাশ ম্যাচ ফ্লো ডিস্টিন্ট অপারেটর অর্ডার-সংরক্ষণের নয়।

যদিও, আমি নিশ্চিত নই (এবং সন্দেহ নেই) যদি এটি সত্যই অর্ডার দেওয়ার নিশ্চয়তা দেয়।

আপনি অনেক ক্ষেত্রে অর্ডার সংরক্ষণ পর্যবেক্ষণ করতে পারেন , তবে এটি বাস্তবায়নের বিশদ; কোনও গ্যারান্টি নেই, সুতরাং আপনি এটির উপর নির্ভর করতে পারবেন না। সর্বদা হিসাবে, উপস্থাপনা আদেশ কেবল একটি শীর্ষ-স্তরের ORDER BYধারা দ্বারা গ্যারান্টিযুক্ত হতে পারে ।

উদাহরণ

নীচের স্ক্রিপ্টটি দেখায় যে হ্যাশ ম্যাচ ফ্লো ডিস্ট্রিন্ট অর্ডার সংরক্ষণ করে না। এটি উভয় কলামে 1-50,000 সংখ্যার সাথে মিলিয়ে প্রশ্নের সারণী সেট আপ করে:

IF OBJECT_ID(N'dbo.Updates', N'U') IS NOT NULL
    DROP TABLE dbo.Updates;
GO
CREATE TABLE Updates
(
    UpdateId INT NOT NULL IDENTITY(1,1),
    ObjectId INT NOT NULL,

    CONSTRAINT PK_Updates_UpdateId PRIMARY KEY (UpdateId)
);
GO
INSERT dbo.Updates (ObjectId)
SELECT TOP (50000)
    ObjectId =
        ROW_NUMBER() OVER (
            ORDER BY C1.[object_id]) 
FROM sys.columns AS C1
CROSS JOIN sys.columns AS C2
ORDER BY
    ObjectId;

পরীক্ষার ক্যোয়ারীটি হ'ল:

DECLARE @Rows bigint = 50000;

-- Optimized for 1 row, but will be 50,000 when executed
SELECT DISTINCT TOP (@Rows)
    U.ObjectId 
FROM dbo.Updates AS U
WHERE 
    U.UpdateId > 0
OPTION (OPTIMIZE FOR (@Rows = 1));

আনুমানিক পরিকল্পনাটি একটি সূচী অনুসন্ধান এবং প্রবাহ পৃথকভাবে দেখায়:

আনুমানিক পরিকল্পনা

আউটপুট অবশ্যই এটি দিয়ে শুরু করার আদেশ দেওয়া হয়েছে বলে মনে হচ্ছে:

ফলাফলের শুরু

... তবে আরও নীচের মানগুলি 'নিখোঁজ' হতে শুরু করে:

প্যাটার্ন ভেঙে

...এবং শেষ পর্যন্ত:

বিশৃঙ্খলা ফেটে যায়

এই বিশেষ ক্ষেত্রে ব্যাখ্যাটি হ'ল হ্যাশ অপারেটরটি ছড়িয়ে পড়ে:

মৃত্যুদণ্ড কার্যকর করার পরিকল্পনা

পার্টিশনটি একবার ছড়িয়ে পড়লে একই পার্টিশনে থাকা সমস্ত সারিও ছড়িয়ে পড়ে। স্পিলযুক্ত পার্টিশনগুলি পরে প্রক্রিয়া করা হয়, এই প্রত্যাশা ভঙ্গ করে যে স্বতন্ত্র মানগুলির মুখোমুখি হয় তত্ক্ষণাত তারা প্রাপ্ত ক্রমের সাথে সাথে নির্গত হবে।


আপনি চান অর্ডার করা ফলাফল উত্পাদন করতে একটি দক্ষ ক্যোয়ারী লেখার অনেকগুলি উপায় রয়েছে যেমন পুনরাবৃত্তি বা কার্সার ব্যবহার করে। তবে এটি হ্যাশ ম্যাচ ফ্লো ডিস্টিন্ট ব্যবহার করে করা যাবে না ।


11

আমি এই উত্তরের সাথে অসন্তুষ্ট কারণ সঠিক ফলাফলের গ্যারান্টিযুক্ত ফলাফলগুলি সহ আমি একটি প্রবাহ স্বতন্ত্র অপারেটরটি পরিচালনা করতে পারিনি। তবে, আমার একটি বিকল্প রয়েছে যা সঠিক ফলাফলের পাশাপাশি ভাল পারফরম্যান্স পাবে। দুর্ভাগ্যক্রমে এটির প্রয়োজন যে টেবিলে একটি অবিবাহিত সূচক তৈরি করা উচিত।

আমি যে কলামগুলি করতে পারছিলাম তার সংমিশ্রনের কথা চিন্তা করার চেষ্টা করে ORDER BYএবং এগুলিতে প্রয়োগ DISTINCTকরার পরে সঠিক ফলাফল পেতে আমি এই সমস্যার কাছে পৌঁছেছি । UpdateIdপ্রতি ObjectIdসাথে সর্বনিম্ন মানটিও ObjectIdএরকম একটি সমন্বয়। তবে, সরাসরি সর্বনিম্ন জিজ্ঞাসা UpdateIdকরার ফলে টেবিল থেকে সমস্ত সারি পড়ার ফলস্বরূপ মনে হয়। পরিবর্তে, আমরা পরোক্ষভাবে UpdateIdঅন্য টেবিলে যোগ দিয়ে ন্যূনতম মান জিজ্ঞাসা করতে পারি । ধারণাটি হ'ল Updatesসারণিটি যাতে স্ক্যান করা হয় , এমন কোনও সারি ছুঁড়ে ফেলা হয় যার UpdateIdজন্য সেই সারিটির সর্বনিম্ন মান হয় না ObjectIdএবং প্রথম 100 টি সারি রাখে। ডেটা বিতরণের আপনার বর্ণনার ভিত্তিতে আমাদের খুব বেশি সারি ছড়িয়ে দেওয়ার দরকার নেই।

ডেটা প্রস্তুতির জন্য, আমি প্রতিটি স্বতন্ত্র অবজেক্টআইডের জন্য 2 টি সারি দিয়ে একটি মিলিতে 1 মিলিয়ন সারি রেখেছি:

INSERT INTO Updates WITH (TABLOCK)
SELECT t.RN / 2
FROM 
(
    SELECT TOP 1000000 -1 + ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
    FROM master..spt_values t1
    CROSS JOIN master..spt_values t2
) t;

CREATE INDEX IX On Updates (Objectid, UpdateId);

অবিচ্ছিন্ন সূচক চালু Objectidএবং UpdateIdএটি গুরুত্বপূর্ণ। এটা আমাদের দক্ষতার সারি যে ন্যূনতম হবে না বর্জন করতে পারবেন UpdateIdপ্রতি Objectid। উপরের বর্ণনার সাথে মেলে এমন একটি ক্যোয়ারী লেখার অনেকগুলি উপায় রয়েছে। এখানে ব্যবহারের মতো একটি উপায় NOT EXISTS:

DECLARE @fromUpdateId INT = 9999;
SELECT ObjectId
FROM (
    SELECT DISTINCT TOP 100 u1.UpdateId, u1.ObjectId
    FROM Updates u1
    WHERE UpdateId > @fromUpdateId
    AND NOT EXISTS (
        SELECT 1
        FROM Updates u2
        WHERE u2.UpdateId > @fromUpdateId
        AND u1.ObjectId = u2.ObjectId
        AND u2.UpdateId < u1.UpdateId
    )
    ORDER BY u1.UpdateId, u1.ObjectId
) t;

এখানে ক্যোয়ারী পরিকল্পনার একটি চিত্র :

জিজ্ঞাসা পরিকল্পনা

সেরা ক্ষেত্রে এসকিউএল সার্ভার কেবলমাত্র অনাবৃত তালিকা অনুসারে ১০০ সূচক চাইবে। খুব দুর্ভাগ্যজনক হওয়ার অনুকরণে আমি ক্লায়েন্টকে প্রথম 5000 সারি ফেরত দেওয়ার জন্য ক্যোয়ারী পরিবর্তন করেছি। এর ফলস্বরূপ 9999 সূচক সন্ধান করা হয়েছে, সুতরাং এটি পৃথক হিসাবে গড়ে 100 টি সারি পাওয়ার মতো ObjectId। এখানে থেকে আউটপুট SET STATISTICS IO, TIME ON:

সারণী 'আপডেট'। স্ক্যান গণনা 10000, যৌক্তিক পঠন 31900, শারীরিক 0 পড়ছে

এসকিউএল সার্ভার এক্সিকিউশন টাইমস: সিপিইউ সময় = 31 এমএস, অতিবাহিত সময় = 42 এমএস।


9

আমি প্রশ্নটি পছন্দ করি - ফ্লো ডিস্টিন্ট আমার প্রিয় অপারেটরগুলির মধ্যে একটি।

এখন, গ্যারান্টি হ'ল সমস্যা। যখন আপনি এফডি অপারেটরটিকে সিক্রেট অপারেটারের কাছ থেকে অর্ডারযুক্ত ফ্যাশনে সারিগুলি টানানোর বিষয়ে চিন্তা করেন, প্রতিটি সারিটি অনন্য হিসাবে নির্ধারিত করে তা উত্পাদন করে, এটি আপনাকে সঠিক ক্রমে সারিগুলি দেবে। তবে এমন কিছু পরিস্থিতি থাকতে পারে যেখানে এফডি একসাথে একক সারি পরিচালনা করে না তা জানা শক্ত।

তাত্ত্বিকভাবে, এফডি সিকের কাছ থেকে 100 টি সারি অনুরোধ করতে পারে এবং যা প্রয়োজন তার প্রয়োজনে সেগুলি উত্পাদন করতে পারে।

ক্যোয়ারী ইঙ্গিত দেয় OPTION (FAST 1, MAXDOP 1) সহায়তা করতে পারে, কারণ এটি সিক অপারেটরের কাছ থেকে প্রয়োজনের চেয়ে বেশি সারি পাওয়া এড়াবে। যদিও এটি একটি গ্যারান্টি ? বেশ না। এটি এখনও একবারে সারির একটি পৃষ্ঠা বা এর মতো কোনও কিছু টেনে আনার সিদ্ধান্ত নিতে পারে।

আমি মনে করি OPTION (FAST 1, MAXDOP 1), আপনার OFFSETসংস্করণটি আপনাকে অর্ডার সম্পর্কে প্রচুর আত্মবিশ্বাস দেবে , তবে এটি কোনও গ্যারান্টি নয়।


আমি এটি বুঝতে পেরেছি, সমস্যাটি হ'ল ফ্লো ডিস্টিন্ট অপারেটর একটি হ্যাশ টেবিল ব্যবহার করে যা ডিস্কে ছড়িয়ে দিতে পারে। যখন একটি স্পিল থাকে, তখনও র‌্যামে থাকা অংশটি ব্যবহার করে যে সারিগুলি প্রক্রিয়া করা যায় তা তত্ক্ষণাত প্রক্রিয়া করা হয়, তবে স্পিডযুক্ত ডেটা ডিস্ক থেকে ফিরে না পড়া পর্যন্ত অন্যান্য সারিগুলি প্রক্রিয়াজাত করা হয় না। আমি যা বলতে পারি তা থেকে, কোনও হ্যাশ টেবিল ব্যবহার করা কোনও অপারেটর (যেমন একটি হ্যাশ যোগদান) এর স্পিলিং আচরণের কারণে অর্ডার সংরক্ষণের গ্যারান্টিযুক্ত নয়।
sam.bishop

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