ব্যবহারকারীর সংজ্ঞায়িত ফাংশন সহ অপ্টিমাইজেশন সমস্যা


26

এসকিউএল সার্ভার কেন কেবলমাত্র একটি সারি আনতে হবে যদিও সারণীতে প্রতিটি মানের জন্য ব্যবহারকারীর সংজ্ঞায়িত ফাংশনটি কল করার সিদ্ধান্ত নেয় তা বুঝতে আমার সমস্যা হয়। আসল এসকিউএল অনেক বেশি জটিল, তবে আমি সমস্যাটি এখানে কমাতে সক্ষম হয়েছি:

select  
    S.GROUPCODE,
    H.ORDERCATEGORY
from    
    ORDERLINE L
    join ORDERHDR H on H.ORDERID = L.ORDERID
    join PRODUCT P  on P.PRODUCT = L.PRODUCT    
    cross apply dbo.GetGroupCode (P.FACTORY) S
where   
    L.ORDERNUMBER = 'XXX/YYY-123456' and
    L.RMPHASE = '0' and
    L.ORDERLINE = '01'

এই ক্যোয়ারির জন্য, এসকিউএল সার্ভার অর্ডারলাইন থেকে প্রাপ্ত সারিগুলির অনুমান এবং প্রকৃত সংখ্যা 1 (যদিও এটি প্রাথমিক কী) যদিও উত্পাদিত সারণীতে বিদ্যমান প্রতিটি একক মানের জন্য getGroupCode ফাংশন কল করার সিদ্ধান্ত নিয়েছে:

অনুসন্ধান পরিকল্পনা

পরিকল্পনার এক্সপ্লোরার একই পরিকল্পনার সারি গণনা দেখায়:

পরিকল্পনা এক্সপ্লোরার টেবিল:

ORDERLINE: 1.5M rows, primary key: ORDERNUMBER + ORDERLINE + RMPHASE (clustered)
ORDERHDR:  900k rows, primary key: ORDERID (clustered)
PRODUCT:   6655 rows, primary key: PRODUCT (clustered)

স্ক্যানের জন্য ব্যবহৃত সূচকটি হ'ল:

create unique nonclustered index PRODUCT_FACTORY on PRODUCT (PRODUCT, FACTORY)

ফাংশনটি আসলে কিছুটা জটিল, তবে একই জিনিসটি ডামি মাল্টি-স্টেটমেন্ট ফাংশনটির সাথে ঘটে:

create function GetGroupCode (@FACTORY varchar(4))
returns @t table(
    TYPE        varchar(8),
    GROUPCODE   varchar(30)
)
as begin
    insert into @t (TYPE, GROUPCODE) values ('XX', 'YY')
    return
end

এসকিউএল সার্ভারকে শীর্ষ 1 পণ্য আনতে বাধ্য করে আমি পারফরম্যান্সটি "ফিক্স" করতে সক্ষম হয়েছি, যদিও 1 সর্বাধিক যা সন্ধান করা যায়:

select  
    S.GROUPCODE,
    H.ORDERCAT
from    
    ORDERLINE L
    join ORDERHDR H
        on H.ORDERID = M.ORDERID
    cross apply (select top 1 P.FACTORY from PRODUCT P where P.PRODUCT = L.PRODUCT) P
    cross apply dbo.GetGroupCode (P.FACTORY) S
where   
    L.ORDERNUMBER = 'XXX/YYY-123456' and
    L.RMPHASE = '0' and
    L.ORDERLINE = '01'

তারপরে পরিকল্পনার আকারটিও এমন কিছুতে পরিবর্তিত হয় যা আমি প্রত্যাশা করি এটি মূলত:

শীর্ষের সাথে ক্যোয়ারী প্ল্যান

আমি আরও জানালাম যে, ক্লাস্টারযুক্ত সূচকের তুলনায় PRODUCT_FACTORY সূচকটি PRODUCT_PK এর চেয়ে ছোট হবে তবে তারপরেও উত্পাদনটি জিজ্ঞাসাবাদকে PRODUCT_PK ব্যবহার করতে বাধ্য করা সত্ত্বেও, ফাংশনটিতে 6655 কল সহ পরিকল্পনাটি এখনও মূল হিসাবে একই।

যদি আমি ORDERHDR পুরোপুরি ছেড়ে চলে যাই তবে প্রথমে অর্ডারলাইন এবং প্রোডাক্টের মধ্যে নেস্টেড লুপ দিয়ে প্ল্যান শুরু হবে এবং ফাংশনটি কেবল একবার ডাকা হবে।

আমি বুঝতে চাই যে এর কারণগুলি কী হতে পারে যেহেতু প্রাথমিক কীগুলি ব্যবহার করে সমস্ত ক্রিয়াকলাপ সম্পন্ন হয় এবং কীভাবে এটি ঠিক করা যায় যদি এটি আরও জটিল প্রশ্নে ঘটে তবে এটি সহজে সমাধান করা যায় না।

সম্পাদনা করুন: সারণী বিবৃতি তৈরি করুন:

CREATE TABLE dbo.ORDERHDR(
    ORDERID varchar(8) NOT NULL,
    ORDERCATEGORY varchar(2) NULL,
    CONSTRAINT ORDERHDR_PK PRIMARY KEY CLUSTERED (ORDERID)
)

CREATE TABLE dbo.ORDERLINE(
    ORDERNUMBER varchar(16) NOT NULL,
    RMPHASE char(1) NOT NULL,
    ORDERLINE char(2) NOT NULL,
    ORDERID varchar(8) NOT NULL,
    PRODUCT varchar(8) NOT NULL,
    CONSTRAINT ORDERLINE_PK PRIMARY KEY CLUSTERED (ORDERNUMBER,ORDERLINE,RMPHASE)
)

CREATE TABLE dbo.PRODUCT(
    PRODUCT varchar(8) NOT NULL,
    FACTORY varchar(4) NULL,
    CONSTRAINT PRODUCT_PK PRIMARY KEY CLUSTERED (PRODUCT)
)

উত্তর:


30

আপনি যে পরিকল্পনাটি করেন তা পেতে মূলত তিনটি প্রযুক্তিগত কারণ রয়েছে:

  1. অপ্টিমাইজারের ব্যয়বহুল কাঠামোর কোনও ইন -ইনলাইন ফাংশনগুলির জন্য সত্যিকারের সমর্থন নেই । এটি কতটা ব্যয়বহুল হতে পারে তা দেখার জন্য এটি ফাংশন সংজ্ঞাটির ভিতরে দেখার কোনও প্রচেষ্টা করে না, এটি কেবলমাত্র একটি খুব সামান্য নির্দিষ্ট ব্যয় নির্ধারণ করে, এবং অনুমান করে যে ফাংশনটি প্রতিবার যখন বলা হবে তখন 1 সারি আউটপুট তৈরি করবে produce এই উভয় মডেলিং অনুমান খুব সম্পূর্ণরূপে অনিরাপদ। স্থায়ী 1-সারির অনুমানটি স্থির 100-সারির অনুমানের সাথে প্রতিস্থাপন করা হওয়ায় নতুন কার্ডিনালটি অনুমানকারী সক্ষম হয়ে 2014 সালে পরিস্থিতি খুব সামান্য উন্নতি হয়েছে। অন-ইনলাইন ফাংশনগুলির সামগ্রীর ব্যয় করার জন্য এখনও কোনও সমর্থন নেই।
  2. এসকিউএল সার্ভার শুরুতে সংঘর্ষে যোগদান করে এবং একটি একক অভ্যন্তরীণ এন-অ্যারি লজিকাল যোগদানের জন্য প্রয়োগ করে। এটি পরে অর্ডারগুলিতে যোগদানের বিষয়ে অপ্টিমাইজার যুক্তিকে সহায়তা করে। প্রার্থীদের যোগদানের আদেশগুলিতে একক এন-অ্যারি যোগ প্রসারণটি পরে আসে এবং এটি মূলত হিউরিস্টিকের উপর ভিত্তি করে। উদাহরণস্বরূপ, অভ্যন্তরীণ যোগদানগুলি বাহ্যিক যোগদানের আগে আসে, ছোট টেবিলগুলি এবং বড় টেবিলগুলির আগে নির্বাচক যোগদান করে এবং কম নির্বাচিত যোগদান করে, ইত্যাদি।
  3. যখন এসকিউএল সার্ভার ব্যয়ভিত্তিক অপ্টিমাইজেশন সম্পাদন করে, স্বল্প-ব্যয়ের প্রশ্নগুলি অপ্টিমাইজ করে খুব বেশি সময় ব্যয় করার সম্ভাবনা হ্রাস করতে এটি প্রচেষ্টাটি pচ্ছিক পর্যায়ে বিভক্ত করে। তিনটি প্রধান পর্যায় রয়েছে, 0 অনুসন্ধান করুন, 1 অনুসন্ধান করুন এবং 2 অনুসন্ধান করুন। প্রতিটি পর্বে প্রবেশের শর্ত থাকে এবং পরবর্তী ধাপগুলি পূর্ববর্তীগুলির চেয়ে আরও বেশি অপ্টিমাইজার অনুসন্ধান সক্ষম করে। আপনার ক্যোয়ারীটি সর্বনিম্ন-সক্ষম অনুসন্ধানের পর্যায়ে, পর্বের জন্য যোগ্যতা অর্জন করে 0. একটি কম পর্যায়ে কম খরচের পরিকল্পনা সেখানে পাওয়া গেছে যে পরবর্তী পর্যায়ে প্রবেশ করা হয়নি।

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

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

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

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

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

খালি টেবিলগুলিতে অনুসন্ধান 0 টি অক্ষম করে পরিকল্পনা করুন

সন্ধান 0 পরিকল্পনা নির্বাচন, প্রারম্ভিক অপ্টিমাইজার সমাপ্তি বা ইউডিএফগুলির ব্যয় উন্নত করার পক্ষে কোনও সমর্থনযোগ্য উপায় নেই (এর জন্য এসকিউএল সার্ভার 2014 সিই মডেলের সীমিত বর্ধন বাদে)। এটি পরিকল্পনা গাইড, ম্যানুয়াল ক্যোয়ারী পুনর্লিখনগুলি ( TOP (1)ধারণা সহ অন্তর্বর্তী অস্থায়ী টেবিলগুলি ব্যবহার করে) এবং নন-ইনলাইন ফাংশনগুলির মতো খারাপ কোস্টেড 'ব্ল্যাক বক্সগুলি' (একটি QO দৃষ্টিকোণ থেকে) এড়িয়ে চলে।

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

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


24

দেখে মনে হচ্ছে এটি অপটিমাইজারের ব্যয়ভিত্তিক সিদ্ধান্ত তবে একটি খারাপ সিদ্ধান্ত bad

আপনি যদি উত্পাদনে 50000 সারি যুক্ত করেন তবে অপ্টিমাইজারটি মনে করে যে স্ক্যানটি খুব বেশি কাজ করেছে এবং আপনাকে তিনটি সন্ধান এবং ইউডিএফকে একটি কল দিয়ে একটি পরিকল্পনা দেয়।

আমি প্ল্যান্টটি PRODU65৫৫ টি সারিটির জন্য PRODUCT এ পাব

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

প্রোডাক্টে 50000 সারি দিয়ে আমি পরিবর্তে এই পরিকল্পনাটি পাই।

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

আমি অনুমান করি যে ইউডিএফ কল করার জন্য ব্যয়টি চূড়ান্তভাবে হ্রাস করা হয়নি।

এই ক্ষেত্রে সূক্ষ্মভাবে কাজ করে এমন একটি কাজ হ'ল ইউডিএফের বিরুদ্ধে বাইরের প্রয়োগের জন্য ক্যোয়ারী পরিবর্তন করা। টেবিল PRODUCT এ কতগুলি সারি থাকুক না কেন আমি ভাল পরিকল্পনা পেয়েছি।

select  
    S.GROUPCODE,
    H.ORDERCATEGORY
from    
    ORDERLINE L
    join ORDERHDR H on H.ORDERID = L.ORDERID
    join PRODUCT P  on P.PRODUCT = L.PRODUCT    
    outer apply dbo.GetGroupCode (P.FACTORY) S
where   
    L.ORDERNUMBER = 'XXX/YYY-123456' and
    L.RMPHASE = '0' and
    L.ORDERLINE = '01' and
    S.GROUPCODE is not null

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

আপনার ক্ষেত্রে সর্বোত্তম কাজটি সম্ভবত আপনার টেম্পল টেবিলের মধ্যে প্রয়োজনীয় মানগুলি পাওয়া এবং তারপরে ইউডিএফের সাথে ক্রস প্রয়োগ করে টেম্প টেবিলটি জিজ্ঞাসা করা। এইভাবে আপনি নিশ্চিত যে ইউডিএফ প্রয়োজনীয়তার চেয়ে বেশি কার্যকর করা হবে না।

select  
    P.FACTORY,
    H.ORDERCATEGORY
into #T
from    
    ORDERLINE L
    join ORDERHDR H on H.ORDERID = L.ORDERID
    join PRODUCT P  on P.PRODUCT = L.PRODUCT
where   
    L.ORDERNUMBER = 'XXX/YYY-123456' and
    L.RMPHASE = '0' and
    L.ORDERLINE = '01'

select  
    S.GROUPCODE,
    T.ORDERCATEGORY
from #T as T
  cross apply dbo.GetGroupCode (T.FACTORY) S

drop table #T

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

select S.GROUPCODE,
       T.ORDERCATEGORY
from (
     select top(2147483647)
         P.FACTORY,
         H.ORDERCATEGORY
     from    
         ORDERLINE L
         join ORDERHDR H on H.ORDERID = L.ORDERID
         join PRODUCT P  on P.PRODUCT = L.PRODUCT    
     where   
         L.ORDERNUMBER = 'XXX/YYY-123456' and
         L.RMPHASE = '0' and
         L.ORDERLINE = '01'
     ) as T
  cross apply dbo.GetGroupCode (T.FACTORY) S

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

আমি বুঝতে চাই যে এর কারণগুলি কী হতে পারে যেহেতু প্রাথমিক কীগুলি ব্যবহার করে সমস্ত ক্রিয়াকলাপ সম্পন্ন হয় এবং কীভাবে এটি ঠিক করা যায় যদি এটি আরও জটিল প্রশ্নে ঘটে তবে এটি সহজে সমাধান করা যায় না।

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

একটি অতিরিক্ত পর্যবেক্ষণ ছিল যে আপনার ক্যোয়ারী এসকিউএল সার্ভারে একটি নতুন পরিকল্পনা পেয়েছে 2014 নতুন কার্ডিনালিটি অনুমানকারী সাথে। এটি কারণ এসকিউএল সার্ভার ২০১২ এবং এর আগের হিসাবে ইউডিএফ-তে প্রতিটি কলের জন্য সারিগুলির আনুমানিক সংখ্যা 1 এর পরিবর্তে 100 হয়। তবে এটি এখনও স্ক্যান সংস্করণ এবং পরিকল্পনার সিক সংস্করণের মধ্যে একই ব্যয়ভিত্তিক সিদ্ধান্ত নেবে। প্রোডাক্টে 500 টিরও কম (আমার ক্ষেত্রে 497) সারি থাকলে আপনি এসকিউএল সার্ভার ২০১৪-তেও পরিকল্পনার স্ক্যান সংস্করণ পাবেন।


2
কোনওভাবে এসকিউএল বিটসে অ্যাডাম মাচানিকের অধিবেশনটির কথা মনে করিয়ে দেয়: sqlbit.com/Sessions/Event14/…
জেমস জেড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.