আমি কীভাবে একটি টি-এসকিউএল সঞ্চিত পদ্ধতিতে alচ্ছিক পরামিতিগুলি ব্যবহার করতে পারি?


185

আমি একটি টেবিলের মাধ্যমে অনুসন্ধান করতে একটি সঞ্চিত পদ্ধতি তৈরি করছি। আমার কাছে অনেকগুলি অনুসন্ধানের ক্ষেত্র রয়েছে, এর সবগুলি alচ্ছিক। কোনও হস্তান্তরিত পদ্ধতি তৈরি করার কোনও উপায় আছে যা এটি পরিচালনা করবে? ধরা যাক আমার চারটি ক্ষেত্র সহ একটি টেবিল রয়েছে: আইডি, ফার্স্টনাম, লাস্টনাম এবং শিরোনাম। আমি এরকম কিছু করতে পারি:

CREATE PROCEDURE spDoSearch
    @FirstName varchar(25) = null,
    @LastName varchar(25) = null,
    @Title varchar(25) = null
AS
    BEGIN
        SELECT ID, FirstName, LastName, Title
        FROM tblUsers
        WHERE
            FirstName = ISNULL(@FirstName, FirstName) AND
            LastName = ISNULL(@LastName, LastName) AND
            Title = ISNULL(@Title, Title)
    END

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


এখানে একবার দেখুন: স্ট্যাকওভারফ্লো.com
মারিও আইস

2
যেখানে বিবৃতি অনুসরণ করার চেষ্টা করুন: codeইসনুল (ফার্স্টনাম, ') = আইএসএনএলএল (@ ফার্স্টনাম,' ') - এটি প্রতিটি এনইউএলকে একটি খালি স্ট্রিংয়ে পরিণত করবে এবং এগুলিকে EQ এর মাধ্যমে তুলনা করা যেতে পারে। অপারেটর. ইনপুট প্যারামিটারটি যদি শূন্য থাকে তবে আপনি যদি সমস্ত শিরোনাম পেতে চান, তবে এর মতো কিছু চেষ্টা করুন: codeফার্স্টনাম = @ ফার্স্টনাম বা @ ফার্স্টনাম নাল।
বাহি

উত্তর:


257

প্রদত্ত প্যারামিটারের উপর ভিত্তি করে गतिशीलভাবে অনুসন্ধানগুলি পরিবর্তন করা একটি জটিল বিষয় এবং এটি কেবল খুব সামান্যতম পার্থক্য থাকা সত্ত্বেও এক উপায়ে এটি করা বিশাল পারফরম্যান্সের প্রভাব ফেলতে পারে। মূলটি হ'ল একটি সূচক ব্যবহার করা, কমপ্যাক্ট কোডটি উপেক্ষা করা, কোড পুনরাবৃত্তি করার বিষয়ে চিন্তিত হওয়া উপেক্ষা করার জন্য আপনাকে অবশ্যই একটি ভাল ক্যোয়ারি এক্সিকিউশন প্ল্যান তৈরি করতে হবে (একটি সূচক ব্যবহার করুন)।

এটি পড়ুন এবং সমস্ত পদ্ধতি বিবেচনা করুন। আপনার সেরা পদ্ধতিটি আপনার পরামিতিগুলি, আপনার ডেটা, আপনার স্কিমা এবং আপনার প্রকৃত ব্যবহারের উপর নির্ভর করবে:

এরল্যান্ড সোমমারস্কোগ দ্বারা টি-এসকিউএল এ গতিশীল অনুসন্ধানের শর্তাদি

আর্ল্যান্ড সোমমারস্কোগের ডাইনামিক এসকিউএল এর অভিশাপ এবং আশীর্বাদ

আপনার যদি সঠিক এসকিউএল সার্ভার ২০০৮ সংস্করণ (এসকিউএল ২০০৮ এসপি 1 সিই 5 (10.0.2746) এবং তারপরে) থাকে তবে আপনি এই সূক্ষ্ম কৌশলটি আসলে একটি সূচক ব্যবহার করতে পারেন:

যোগ OPTION (RECOMPILE)আপনার প্রশ্নের সম্মুখের, Erland এর নিবন্ধ দেখুন , এবং SQL সার্ভার সমাধান হবে ORমধ্যে থেকে (@LastName IS NULL OR LastName= @LastName)সামনে ক্যোয়ারী পরিকল্পনা স্থানীয় ভেরিয়েবল রানটাইম মান উপর ভিত্তি করে তৈরি করা হয়, এবং একটি সূচক ব্যবহার করা যাবে।

এটি যে কোনও এসকিউএল সার্ভার সংস্করণে (সঠিক ফলাফল প্রত্যাবর্তন করবে) কাজ করবে তবে আপনি এসকিউএল ২০০৮ এসপি 1 সিই 5 (10.0.2746) এবং তারপরে থাকলে কেবলমাত্র বিকল্প (পুনরুদ্ধার) অন্তর্ভুক্ত করুন। অপশন (পুনরুদ্ধার) আপনার ক্যোয়ারীটি পুনরায় সংকলন করবে, কেবল তালিকাভুক্ত ভেরিসনটি স্থানীয় ভেরিয়েবলগুলির বর্তমান রান টাইম মানগুলির উপর ভিত্তি করে এটি পুনরায় সংকলন করবে, যা আপনাকে সেরা পারফরম্যান্স দেবে। যদি এসকিউএল সার্ভার ২০০৮ এর সংস্করণে না থাকে তবে কেবল সেই লাইনটি ছেড়ে দিন।

CREATE PROCEDURE spDoSearch
    @FirstName varchar(25) = null,
    @LastName varchar(25) = null,
    @Title varchar(25) = null
AS
    BEGIN
        SELECT ID, FirstName, LastName, Title
        FROM tblUsers
        WHERE
                (@FirstName IS NULL OR (FirstName = @FirstName))
            AND (@LastName  IS NULL OR (LastName  = @LastName ))
            AND (@Title     IS NULL OR (Title     = @Title    ))
        OPTION (RECOMPILE) ---<<<<use if on for SQL 2008 SP1 CU5 (10.0.2746) and later
    END

15
AND / OR এর অগ্রাধিকার সম্পর্কে সতর্ক থাকুন। এবং এর চেয়ে ও এর চেয়ে বেশি প্রাধান্য রয়েছে, সুতরাং সঠিক বন্ধনী ছাড়াই এই উদাহরণটি প্রত্যাশিত ফলাফল আনবে না ... সুতরাং এটি চিৎকার করে উঠবে: (@ প্রথম নামটি নাল বা (প্রথম নাম = @ প্রথম নাম)) এবং (লাস্টনামিস নাল অর্ড বা লাস্টনাম = @LastName)) এবং (@TitleIS শূন্য অথবা (title = @Title))
Bliek

... (@ প্রথম নামটি নাল বা (প্রথম নাম = @ প্রথম নাম) হওয়া উচিত ... (ফার্স্টনাম = কোলেসেস (@ প্রথম নাম,
ফার্স্টনাম

প্রথম বন্ধনী ভুলে যাবেন না, অন্যথায় এটি কাজ করবে না।
পাবলো ক্যারাসকো হার্নান্দেজ

27

@ কেএম এর উত্তর যতদূর যায় উত্তম তবে তার প্রাথমিক পরামর্শের একটিতে পুরোপুরি অনুসরণ করতে ব্যর্থ হয়;

..., কমপ্যাক্ট কোডটি উপেক্ষা করুন, কোড পুনরাবৃত্তি করার বিষয়ে উদ্বেগকে উপেক্ষা করুন, ...

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

CREATE PROCEDURE spDoSearch
    @FirstName varchar(25) = null,
    @LastName varchar(25) = null,
    @Title varchar(25) = null
AS
BEGIN

    IF (@FirstName IS NOT NULL AND @LastName IS NULL AND @Title IS NULL)
        -- Search by first name only
        SELECT ID, FirstName, LastName, Title
        FROM tblUsers
        WHERE
            FirstName = @FirstName

    ELSE IF (@FirstName IS NULL AND @LastName IS NOT NULL AND @Title IS NULL)
        -- Search by last name only
        SELECT ID, FirstName, LastName, Title
        FROM tblUsers
        WHERE
            LastName = @LastName

    ELSE IF (@FirstName IS NULL AND @LastName IS NULL AND @Title IS NOT NULL)
        -- Search by title only
        SELECT ID, FirstName, LastName, Title
        FROM tblUsers
        WHERE
            Title = @Title

    ELSE IF (@FirstName IS NOT NULL AND @LastName IS NOT NULL AND @Title IS NULL)
        -- Search by first and last name
        SELECT ID, FirstName, LastName, Title
        FROM tblUsers
        WHERE
            FirstName = @FirstName
            AND LastName = @LastName

    ELSE
        -- Search by any other combination
        SELECT ID, FirstName, LastName, Title
        FROM tblUsers
        WHERE
                (@FirstName IS NULL OR (FirstName = @FirstName))
            AND (@LastName  IS NULL OR (LastName  = @LastName ))
            AND (@Title     IS NULL OR (Title     = @Title    ))

END

এই পদ্ধতির সুবিধাটি হ'ল বিসপোক ক্যোয়ারী দ্বারা পরিচালিত সাধারণ ক্ষেত্রে ক্যোয়ারী যতটা দক্ষ হয় তেমন দক্ষ - অসমর্থিত মাপদণ্ডের দ্বারা কোনও প্রভাব নেই। এছাড়াও, সমস্ত সম্ভাব্য পরিস্থিতি সন্তুষ্ট করার চেষ্টা করার পরিবর্তে সূচি এবং অন্যান্য কার্যকারিতা বর্ধনগুলি নির্দিষ্ট bespoke ক্যোয়ারিতে লক্ষ্যবস্তু করা যেতে পারে।


অবশ্যই প্রতিটি ক্ষেত্রে পৃথক পৃথক সঞ্চিত প্রক্রিয়া লেখা ভাল। তাহলে স্পোফিং এবং পুনঃসংশোধনের বিষয়ে চিন্তা করবেন না।
জোডরেল

5
এটি না বলেই চলতে হবে যে এই পদ্ধতির দ্রুত রক্ষণাবেক্ষণের দুঃস্বপ্ন হয়ে যায়।
আতারিও

3
@ আটারিও রক্ষণাবেক্ষণ বনাম পারফরম্যান্সের একটি সহজ বাণিজ্য, এই উত্তরটি পারফরম্যান্সের দিকে এগিয়ে যায়।
রাইস জোনস

26

আপনি নিম্নলিখিত ক্ষেত্রে করতে পারেন,

CREATE PROCEDURE spDoSearch
   @FirstName varchar(25) = null,
   @LastName varchar(25) = null,
   @Title varchar(25) = null
AS
  BEGIN
      SELECT ID, FirstName, LastName, Title
      FROM tblUsers
      WHERE
        (@FirstName IS NULL OR FirstName = @FirstName) AND
        (@LastNameName IS NULL OR LastName = @LastName) AND
        (@Title IS NULL OR Title = @Title)
END

তবে ডেটা উপর নির্ভর করে কখনও কখনও আরও ভাল গতিশীল ক্যোয়ারী তৈরি করুন এবং তাদের সম্পাদন করুন।


10

পাঁচ বছর দেরিতে পার্টিতে।

এটি গৃহীত উত্তরের প্রদত্ত লিঙ্কগুলিতে উল্লেখ করা হয়েছে, তবে আমি মনে করি এটি এসও-তে একটি স্পষ্ট উত্তরের প্রাপ্য - সরবরাহিত পরামিতিগুলির উপর ভিত্তি করে কোয়েরিটি গতিশীলভাবে তৈরি করা। উদাহরণ:

সেটআপ

-- drop table Person
create table Person
(
    PersonId INT NOT NULL IDENTITY(1, 1) CONSTRAINT PK_Person PRIMARY KEY,
    FirstName NVARCHAR(64) NOT NULL,
    LastName NVARCHAR(64) NOT NULL,
    Title NVARCHAR(64) NULL
)
GO

INSERT INTO Person (FirstName, LastName, Title)
VALUES ('Dick', 'Ormsby', 'Mr'), ('Serena', 'Kroeger', 'Ms'), 
    ('Marina', 'Losoya', 'Mrs'), ('Shakita', 'Grate', 'Ms'), 
    ('Bethann', 'Zellner', 'Ms'), ('Dexter', 'Shaw', 'Mr'),
    ('Zona', 'Halligan', 'Ms'), ('Fiona', 'Cassity', 'Ms'),
    ('Sherron', 'Janowski', 'Ms'), ('Melinda', 'Cormier', 'Ms')
GO

কার্যপ্রণালী

ALTER PROCEDURE spDoSearch
    @FirstName varchar(64) = null,
    @LastName varchar(64) = null,
    @Title varchar(64) = null,
    @TopCount INT = 100
AS
BEGIN
    DECLARE @SQL NVARCHAR(4000) = '
        SELECT TOP ' + CAST(@TopCount AS VARCHAR) + ' *
        FROM Person
        WHERE 1 = 1'

    PRINT @SQL

    IF (@FirstName IS NOT NULL) SET @SQL = @SQL + ' AND FirstName = @FirstName'
    IF (@LastName IS NOT NULL) SET @SQL = @SQL + ' AND FirstName = @LastName'
    IF (@Title IS NOT NULL) SET @SQL = @SQL + ' AND Title = @Title'

    EXEC sp_executesql @SQL, N'@TopCount INT, @FirstName varchar(25), @LastName varchar(25), @Title varchar(64)', 
         @TopCount, @FirstName, @LastName, @Title
END
GO

ব্যবহার

exec spDoSearch @TopCount = 3
exec spDoSearch @FirstName = 'Dick'

পেশাদাররা:

  • লিখতে এবং বুঝতে সহজ
  • নমনীয়তা - সহজেই কৌশলযুক্ত ফিল্টারিংয়ের জন্য ক্যোয়ারী উত্পন্ন করুন (যেমন ডায়নামিক শীর্ষ)

কনস:

  • প্রদত্ত প্যারামিটার, সূচক এবং ডেটা ভলিউমের উপর নির্ভর করে সম্ভাব্য পারফরম্যান্স সমস্যা

সরাসরি উত্তর নয়, তবে সমস্যাটির সাথে সম্পর্কিত বড় ছবি aka

সাধারণত, এই ফিল্টারিং সঞ্চিত পদ্ধতিগুলি প্রায় ভাসমান নয়, তবে কিছু পরিষেবা স্তর থেকে কল করা হচ্ছে। এটি এসকিউএল থেকে পরিষেবা স্তরে ব্যবসায়িক যুক্তি (ফিল্টারিং) সরিয়ে যাওয়ার বিকল্প ছেড়ে দেয়।

একটি উদাহরণ সরবরাহিত ফিল্টারগুলির উপর ভিত্তি করে ক্যোয়ারী উত্পন্ন করতে LINQ2SQL ব্যবহার করছে:

    public IList<SomeServiceModel> GetServiceModels(CustomFilter filters)
    {
        var query = DataAccess.SomeRepository.AllNoTracking;

        // partial and insensitive search 
        if (!string.IsNullOrWhiteSpace(filters.SomeName))
            query = query.Where(item => item.SomeName.IndexOf(filters.SomeName, StringComparison.OrdinalIgnoreCase) != -1);
        // filter by multiple selection
        if ((filters.CreatedByList?.Count ?? 0) > 0)
            query = query.Where(item => filters.CreatedByList.Contains(item.CreatedById));
        if (filters.EnabledOnly)
            query = query.Where(item => item.IsEnabled);

        var modelList = query.ToList();
        var serviceModelList = MappingService.MapEx<SomeDataModel, SomeServiceModel>(modelList);
        return serviceModelList;
    }

পেশাদাররা:

  • সরবরাহকৃত ফিল্টারগুলির উপর ভিত্তি করে গতিময়ভাবে উত্পন্ন উত্স query কোনও প্যারামিটার স্নিফিং বা পুনরায় সংকলনের ইঙ্গিতগুলির প্রয়োজন নেই
  • ওওপি বিশ্বে যারা লেখেন তাদের পক্ষে কিছুটা সহজ
  • সাধারণত পারফরম্যান্স বান্ধব, যেহেতু "সরল" প্রশ্নগুলি জারি করা হবে (যথাযথ সূচীগুলি এখনও প্রয়োজন)

কনস:

  • লাইনকিউ 2 কিউএল সীমাবদ্ধতাগুলি পৌঁছে যেতে পারে এবং লিনকুই 2 সংস্থাগুলিতে একটি ডাউনগ্রেড জোর করে বা কেসের উপর নির্ভর করে খাঁটি এসকিউএল সমাধানে ফিরে যেতে পারে
  • লিনকিউ-এর গাফিল লেখার ফলে ভয়াবহ প্রশ্ন উত্পন্ন হতে পারে (বা অনেক প্রশ্ন, যদি নেভিগেশন সম্পত্তি লোড করা থাকে)

1
নিশ্চিত হয়ে নিন যে আপনার সমস্ত মধ্যবর্তী স্ট্রিংগুলি '' এর পরিবর্তে 'এন' '- আপনি যদি এসকিউএল 8000 অক্ষর অতিক্রম করে থাকেন তবে আপনি কাটা সমস্যার মধ্যে চলে যাবেন।
অ্যালান সিঙ্গফিল্ড

1
এছাড়াও, যদি আপনি ব্যবহারকারীর সরাসরি নির্বাচনের অনুমতি অস্বীকার করেন তবে আপনার স্টোর করা পদ্ধতিতে "মালিক হিসাবে যেমন এক্সকেট" সহ একটি ধারা রাখতে হবে UT আপনি যদি এই ধারাটি ব্যবহার করেন তবে এসকিউএল ইঞ্জেকশনটি এড়াতে সত্যিই সতর্ক হন।
অ্যালান সিঙ্গফিল্ড

8

আপনার WHEREশর্ত প্রসারিত করুন :

WHERE
    (FirstName = ISNULL(@FirstName, FirstName)
    OR COALESCE(@FirstName, FirstName, '') = '')
AND (LastName = ISNULL(@LastName, LastName)
    OR COALESCE(@LastName, LastName, '') = '')
AND (Title = ISNULL(@Title, Title)
    OR COALESCE(@Title, Title, '') = '')

অর্থাত্ বুলিয়ান শর্তের সাথে বিভিন্ন ক্ষেত্রে একত্রিত করুন।


-3

এটিও কাজ করে:

    ...
    WHERE
        (FirstName IS NULL OR FirstName = ISNULL(@FirstName, FirstName)) AND
        (LastName IS NULL OR LastName = ISNULL(@LastName, LastName)) AND
        (Title IS NULL OR Title = ISNULL(@Title, Title))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.