আমি যখন ভেরিয়েবলটি ইনলাইন করব তখন এসকিউএল সার্ভার কেন আরও কার্যকর এক্সিকিউশন পরিকল্পনা ব্যবহার করে?


32

আমার একটি এসকিউএল ক্যোয়ারী রয়েছে যা আমি অনুকূলিত করার চেষ্টা করছি:

DECLARE @Id UNIQUEIDENTIFIER = 'cec094e5-b312-4b13-997a-c91a8c662962'

SELECT 
  Id,
  MIN(SomeTimestamp),
  MAX(SomeInt)
FROM dbo.MyTable
WHERE Id = @Id
  AND SomeBit = 1
GROUP BY Id

MyTable দুটি সূচক রয়েছে:

CREATE NONCLUSTERED INDEX IX_MyTable_SomeTimestamp_Includes
ON dbo.MyTable (SomeTimestamp ASC)
INCLUDE(Id, SomeInt)

CREATE NONCLUSTERED INDEX IX_MyTable_Id_SomeBit_Includes
ON dbo.MyTable (Id, SomeBit)
INCLUDE (TotallyUnrelatedTimestamp)

আমি যখন উপরের লিখিতভাবে ঠিক মতো কোয়েরিটি সম্পাদন করি তখন এসকিউএল সার্ভার প্রথম সূচকটি স্ক্যান করে, ফলস্বরূপ 189,703 লজিকাল রিড এবং একটি 2-3 দ্বিতীয় সময়কাল হয়।

আমি যখন @Idভেরিয়েবলটি ইনলাইন করি এবং আবার কোয়েরিটি সম্পাদন করি , এসকিউএল সার্ভার দ্বিতীয় সূচীর সন্ধান করে, যার ফলে কেবলমাত্র 104 লজিকাল রিড হয় এবং একটি 0.001 দ্বিতীয় সময়কাল (মূলত তাত্ক্ষণিক)।

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

সুতরাং, যখন আমি ভেরিয়েবলটি ইনলাইন করব তখন এসকিউএল সার্ভার কেন আরও ভাল পরিকল্পনা নিয়ে আসে?

উত্তর:


44

এসকিউএল সার্ভারে, যোগ না দেওয়ার প্রাকটিকেটের তিনটি সাধারণ ফর্ম রয়েছে:

একটি সঙ্গে আক্ষরিক মান:

SELECT COUNT(*) AS records
FROM   dbo.Users AS u
WHERE  u.Reputation = 1;

একটি প্যারামিটার সহ :

CREATE PROCEDURE dbo.SomeProc(@Reputation INT)
AS
BEGIN
    SELECT COUNT(*) AS records
    FROM   dbo.Users AS u
    WHERE  u.Reputation = @Reputation;
END;

একটি সঙ্গে স্থানীয় পরিবর্তনশীল :

DECLARE @Reputation INT = 1

SELECT COUNT(*) AS records
FROM   dbo.Users AS u
WHERE  u.Reputation = @Reputation;

ফলাফল

আপনি যখন একটি আক্ষরিক মান ব্যবহার করেন , এবং আপনার পরিকল্পনাটি নয়) তুচ্ছ এবং খ) সরল প্যারামিটারাইজড বা গ) আপনার জোর করে প্যারামিটারাইজেশন চালু করা হয়নি, অপটিমাইজার কেবলমাত্র সেই মানটির জন্য একটি বিশেষ পরিকল্পনা তৈরি করে।

আপনি যখন কোনও প্যারামিটার ব্যবহার করেন , তখন অপ্টিমাইজার সেই প্যারামিটারের জন্য একটি পরিকল্পনা তৈরি করবে (এটিকে প্যারামিটার স্নিফিং বলা হয় ) এবং তারপরে সেই পরিকল্পনাটি পুনরায় ব্যবহার করুন, অনুপস্থিত রিকম্পাইল ইঙ্গিতগুলি, পরিকল্পনার ক্যাশে উচ্ছেদ ইত্যাদি use

আপনি যদি একটি ব্যবহার করেন, তখন স্থানীয় পরিবর্তনশীল , অপটিমাইজার জন্য ... একটি পরিকল্পনা করে তোলে কিছু

আপনি যদি এই ক্যোয়ারীটি চালাচ্ছিলেন:

DECLARE @Reputation INT = 1

SELECT COUNT(*) AS records
FROM   dbo.Users AS u
WHERE  u.Reputation = @Reputation;

পরিকল্পনাটি এর মতো দেখাবে:

পাগল

এবং স্থানীয় ভেরিয়েবলের জন্য সারিগুলির আনুমানিক সংখ্যার মতো দেখতে পাবেন:

পাগল

যদিও ক্যোয়ারী 4,744,427 এর একটি গণনা দেয়।

স্থানীয় ভেরিয়েবলগুলি, অজানা হিসাবে, কার্ডিনালিটির অনুমানের জন্য হিস্টোগ্রামের 'ভাল' অংশটি ব্যবহার করবেন না। তারা ঘনত্ব ভেক্টরের উপর ভিত্তি করে একটি অনুমান ব্যবহার করে।

পাগল

SELECT 5.280389E-05 * 7250739 AS [poo]

এটি আপনাকে দেবে 382.86722457471, যা অনুমানটি অপ্টিমাইজার করে তোলে।

এই অজানা অনুমানগুলি সাধারণত খুব খারাপ অনুমান হয় এবং এটি প্রায়শই খারাপ পরিকল্পনা এবং খারাপ সূচক পছন্দগুলিতে বাড়ে।

এটা ঠিক করা?

আপনার বিকল্পগুলি সাধারণত:

  • ভঙ্গুর সূচক ইঙ্গিত
  • সম্ভাব্য ব্যয়বহুল সংকেতগুলি
  • প্যারামিটারাইজড গতিশীল এসকিউএল
  • একটি সঞ্চিত পদ্ধতি
  • বর্তমান সূচকটি উন্নত করুন

আপনার বিকল্পগুলি বিশেষত:

বর্তমান সূচকের উন্নতি করার অর্থ কোয়েরিতে প্রয়োজনীয় সমস্ত কলাম কভার করার জন্য এটি প্রসারিত করা:

CREATE NONCLUSTERED INDEX IX_MyTable_Id_SomeBit_Includes
ON dbo.MyTable (Id, SomeBit)
INCLUDE (TotallyUnrelatedTimestamp, SomeTimestamp, SomeInt)
WITH (DROP_EXISTING = ON);

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

আরও পঠন

আপনি এখানে প্যারামিটার এম্বেডিং সম্পর্কে আরও পড়তে পারেন:


12

আমি ধরে নিতে চলেছি যে আপনার কাছে ডেটা স্কিউ আছে, আপনি অপটিমাইজারকে কী করতে হবে তা জোর করার জন্য ক্যোয়ারী ইঙ্গিতগুলি ব্যবহার করতে চান না এবং এর সমস্ত সম্ভাব্য ইনপুট মানগুলির জন্য আপনার ভাল পারফরম্যান্স পাওয়া দরকার @Id। আপনি যদি নিম্নলিখিত সূচকগুলি (বা তাদের সমতুল্য) তৈরি করতে ইচ্ছুক হন তবে কোনও সম্ভাব্য ইনপুট মানের জন্য মাত্র কয়েক মুষ্টি যৌক্তিক পাঠের প্রয়োজনীয়তার গ্যারান্টিযুক্ত আপনি একটি কোয়েরি প্ল্যান পেতে পারেন:

CREATE INDEX GetMinSomeTimestamp ON dbo.MyTable (Id, SomeTimestamp) WHERE SomeBit = 1;
CREATE INDEX GetMaxSomeInt ON dbo.MyTable (Id, SomeInt) WHERE SomeBit = 1;

নীচে আমার পরীক্ষার ডেটা রয়েছে। আমি টেবিলের মধ্যে 13 M সারি করা এবং তাদের মধ্যে অর্ধেক প্রণীত একটি মূল্য আছে '3A35EA17-CE7E-4637-8319-4C517B6E48CA'জন্য Idকলাম।

DROP TABLE IF EXISTS dbo.MyTable;

CREATE TABLE dbo.MyTable (
    Id uniqueidentifier,
    SomeTimestamp DATETIME2,
    SomeInt INT,
    SomeBit BIT,
    FILLER VARCHAR(100)
);

INSERT INTO dbo.MyTable WITH (TABLOCK)
SELECT NEWID(), CURRENT_TIMESTAMP, 0, 1, REPLICATE('Z', 100)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

INSERT INTO dbo.MyTable WITH (TABLOCK)
SELECT '3A35EA17-CE7E-4637-8319-4C517B6E48CA', CURRENT_TIMESTAMP, 0, 1, REPLICATE('Z', 100)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

এই ক্যোয়ারীটি প্রথমে কিছুটা অদ্ভুত লাগবে:

DECLARE @Id UNIQUEIDENTIFIER = '3A35EA17-CE7E-4637-8319-4C517B6E48CA'

SELECT
  @Id,
  st.SomeTimestamp,
  si.SomeInt
FROM (
    SELECT TOP (1) SomeInt, Id
    FROM dbo.MyTable
    WHERE Id = @Id
    AND SomeBit = 1
    ORDER BY SomeInt DESC
) si
CROSS JOIN (
    SELECT TOP (1) SomeTimestamp, Id
    FROM dbo.MyTable
    WHERE Id = @Id
    AND SomeBit = 1
    ORDER BY SomeTimestamp ASC
) st;

এটি কয়েকটি যৌক্তিক পাঠ সহ নূন্যতম বা সর্বাধিক মান সন্ধান করার জন্য সূচীগুলির ক্রমটির সুযোগ গ্রহণ করার জন্য ডিজাইন করা হয়েছে। CROSS JOINসেখানে সঠিক ফলাফল পেতে আছে যখন কোন ম্যাচিং সারি নয় @Idমান। এমনকি যদি আমি সারণীর সর্বাধিক জনপ্রিয় মানটিতে ফিল্টার করি (.5.৫ মিলিয়ন সারি মিলে) আমি কেবল 8 টি যৌক্তিক পাঠ পাই:

সারণী 'মাই টেবিল'। স্ক্যান গণনা 2, যৌক্তিক পাঠ 8

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

এখানে চিত্র বর্ণনা লিখুন

উভয় সূচক 0 বা 1 সারি সন্ধান করে। এটি অত্যন্ত দক্ষ, তবে দুটি সূচী তৈরি করা আপনার দৃশ্যের জন্য ওভারকিল হতে পারে। পরিবর্তে আপনি নিম্নলিখিত সূচকটি বিবেচনা করতে পারেন:

CREATE INDEX CoveringIndex ON dbo.MyTable (Id) INCLUDE (SomeTimestamp, SomeInt) WHERE SomeBit = 1;

এখন মূল ক্যোয়ারির ক্যোয়ারী প্ল্যান (anচ্ছিক MAXDOP 1ইঙ্গিত সহ) কিছুটা আলাদা দেখাচ্ছে:

এখানে চিত্র বর্ণনা লিখুন

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

সারণী 'মাই টেবিল'। স্ক্যান কাউন্ট 1, লজিকাল 33757 পড়ে


2

আমি এখানে কেন উত্তর দিতে পারি না , তবে কোয়েরিটি আপনার পছন্দ মতো চালায় তা নিশ্চিত করার দ্রুত এবং নোংরা উপায়:

DECLARE @Id UNIQUEIDENTIFIER = 'cec094e5-b312-4b13-997a-c91a8c662962'
SELECT 
  Id,
  MIN(SomeTimestamp),
  MAX(SomeInt)
FROM dbo.MyTable WITH (INDEX(IX_MyTable_Id_SomeBit_Includes))
WHERE Id = @Id
  AND SomeBit = 1
GROUP BY Id

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

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