WHERE ক্লজে ভেরিয়েবল ব্যবহার কীভাবে এড়ানো যায়


16

এই হিসাবে একটি (সরলীকৃত) সঞ্চিত পদ্ধতি দেওয়া:

CREATE PROCEDURE WeeklyProc(@endDate DATE)
AS
BEGIN
  DECLARE @startDate DATE = DATEADD(DAY, -6, @endDate)
  SELECT
    -- Stuff
  FROM Sale
  WHERE SaleDate BETWEEN @startDate AND @endDate
END

যদি Saleটেবিলটি বড় হয় তবে এটি কার্যকর SELECTকরতে দীর্ঘ সময় নিতে পারে, দৃশ্যত কারণ স্থানীয় ভেরিয়েবলের কারণে অপ্টিমাইজারটি অনুকূলিত করতে পারে না। আমরা SELECTভেরিয়েবলগুলির সাথে অংশটি চালনার পরীক্ষা করেছিলাম তারপরে হার্ড কোডিং তারিখগুলি এবং কার্যকর করার সময়টি ~ 9 মিনিট থেকে 1 সেকেন্ডে চলে যায়।

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

প্রশ্নটি হ'ল, অপটিমাইজারের সাথে সমঝোতা না করার জন্য যেখানে একটি বৃহত্তর ধারাটিতে পরিবর্তনশীলগুলি এড়ানোর জন্য সর্বোত্তম অনুশীলন কোনটি?

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

ভেরিয়েবলগুলিকে পরামিতিগুলিতে পরিণত করতে একটি মোড়ক প্রক্রিয়া ব্যবহার করুন।

প্যারামিটারগুলি স্থানীয় ভেরিয়েবলগুলি একইভাবে অপ্টিমাইজারকে প্রভাবিত করে না।

CREATE PROCEDURE WeeklyProc(@endDate DATE)
AS
BEGIN
   DECLARE @startDate DATE = DATEADD(DAY, -6, @endDate)
   EXECUTE DateRangeProc @startDate, @endDate
END

CREATE PROCEDURE DateRangeProc(@startDate DATE, @endDate DATE)
AS
BEGIN
  SELECT
    -- Stuff
  FROM Sale
  WHERE SaleDate BETWEEN @startDate AND @endDate
END

প্যারামিটারাইজড ডায়নামিক এসকিউএল ব্যবহার করুন।

CREATE PROCEDURE WeeklyProc(@endDate DATE)
AS
BEGIN
  DECLARE @startDate DATE = DATEADD(DAY, -6, @endDate)
  DECLARE @sql NVARCHAR(4000) = N'
    SELECT
      -- Stuff
    FROM Sale
    WHERE SaleDate BETWEEN @startDate AND @endDate
  '
  DECLARE @param NVARCHAR(4000) = N'@startDate DATE, @endDate DATE'
  EXECUTE sp_executesql @sql, @param, @startDate = @startDate, @endDate = @endDate
END

"হার্ড-কোডড" গতিশীল এসকিউএল ব্যবহার করুন।

CREATE PROCEDURE WeeklyProc(@endDate DATE)
AS
BEGIN
  DECLARE @startDate DATE = DATEADD(DAY, -6, @endDate)
  DECLARE @sql NVARCHAR(4000) = N'
    SELECT
      -- Stuff
    FROM Sale
    WHERE SaleDate BETWEEN @startDate AND @endDate
  '
  SET @sql = REPLACE(@sql, '@startDate', CONVERT(NCHAR(10), @startDate, 126))
  SET @sql = REPLACE(@sql, '@endDate', CONVERT(NCHAR(10), @endDate, 126))
  EXECUTE sp_executesql @sql
END

DATEADD()সরাসরি ফাংশনটি ব্যবহার করুন ।

আমি এটি সম্পর্কে আগ্রহী নই কারণ WHERE এ কল করা ফাংশনগুলিও কার্য সম্পাদনকে প্রভাবিত করে।

CREATE PROCEDURE WeeklyProc(@endDate DATE)
AS
BEGIN
  SELECT
    -- Stuff
  FROM Sale
  WHERE SaleDate BETWEEN DATEADD(DAY, -6, @endDate) AND @endDate
END

.চ্ছিক প্যারামিটার ব্যবহার করুন।

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

CREATE PROCEDURE WeeklyProc(@endDate DATE, @startDate DATE = NULL)
AS
BEGIN
  SET @startDate = DATEADD(DAY, -6, @endDate)
  SELECT
    -- Stuff
  FROM Sale
  WHERE SaleDate BETWEEN @startDate AND @endDate
END

-- হালনাগাদ --

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

রান 1 কোনও পরিকল্পনা ছাড়াই। রান 2 ঠিক একই পরামিতিগুলির সাথে রান 1 এর পরে রয়েছে তাই এটি রান 1 থেকে পরিকল্পনাটি ব্যবহার করবে।

নোপ্রোকের সময়গুলি সঞ্চিত পদ্ধতির বাইরে এসএসএমএসে ম্যানুয়ালি নির্বাচন করুন অনুসন্ধানগুলি চালনার জন্য।

টেস্টপ্রোক 1-7 হ'ল মূল প্রশ্নটি।

TestProcA-বি দ্বারা পরামর্শের উপর ভিত্তি করে করা হয় Mikael এরিকসন । ডাটাবেসের কলামটি একটি তারিখ তাই আমি DATETIME হিসাবে প্যারামিটারটি পাস করার চেষ্টা করেছি এবং অন্তর্ভুক্ত ingালাই (টেস্টপ্রোকা) এবং সুস্পষ্ট licitালাই (টেস্টপ্রোকবি) দিয়ে চলছে।

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

    বিক্রয় সারণীতে মোট সারি: 136,424,366

                       রান 1 (এমএস) রান 2 (এমএস)
    প্রক্রিয়া সিপিইউতে বিভক্ত সিপিইউতে বিযুক্ত মন্তব্য
    নোপ্রোক স্থির হয় 6567 62199 2870 719 ধ্রুবকগুলির সাথে ম্যানুয়াল কোয়েরি
    নোপ্রোক ভেরিয়েবল 9314 62424 3993 998 ভেরিয়েবলগুলির সাথে ম্যানুয়াল কোয়েরি
    টেস্টপ্রোক 1 6801 62919 2871 736 হার্ড কোডড ব্যাপ্তি
    পরীক্ষাপ্রোক 2 8955 63190 3915 979 পরামিতি এবং পরিবর্তনশীল পরিসীমা
    প্যারামিটারের পরিসীমা সহ টেস্টপ্রোক 3 8985 63152 3932 987 মোড়ানো পদ্ধতি
    টেস্টপ্রোক 4 9142 63939 3931 977 প্যারামিটারাইজড গতিশীল এসকিউএল
    টেস্টপ্রোক 5 7269 62933 2933 728 হার্ড কোডড গতিশীল এসকিউএল
    testProc6 9266 63421 3915 984 তারিখ DATEADD ব্যবহার করুন
    testProc7 2044 13950 1092 1087 ডামি প্যারামিটার
    টেস্টপ্রোকা 12120 61493 5491 1875 DATETIME এ CAST ছাড়াই DATEADD ব্যবহার করুন
    টেস্টপ্রোকবি 8612 61949 3932 978 DATETIME এ CAST সহ DATEADD ব্যবহার করুন
    টেস্টপ্রসিসি 8861 61651 3917 993 লুকিং টেবিল ব্যবহার করুন, প্রথমে বিক্রয়
    টেস্টপ্রোকড 8625 61740 3994 1031 লুক টেবিল ব্যবহার করুন, সর্বশেষ বিক্রয়

পরীক্ষার কোডটি এখানে।

------ SETUP ------

IF OBJECT_ID(N'testDimDate', N'U') IS NOT NULL DROP TABLE testDimDate
IF OBJECT_ID(N'testProc1', N'P') IS NOT NULL DROP PROCEDURE testProc1
IF OBJECT_ID(N'testProc2', N'P') IS NOT NULL DROP PROCEDURE testProc2
IF OBJECT_ID(N'testProc3', N'P') IS NOT NULL DROP PROCEDURE testProc3
IF OBJECT_ID(N'testProc3a', N'P') IS NOT NULL DROP PROCEDURE testProc3a
IF OBJECT_ID(N'testProc4', N'P') IS NOT NULL DROP PROCEDURE testProc4
IF OBJECT_ID(N'testProc5', N'P') IS NOT NULL DROP PROCEDURE testProc5
IF OBJECT_ID(N'testProc6', N'P') IS NOT NULL DROP PROCEDURE testProc6
IF OBJECT_ID(N'testProc7', N'P') IS NOT NULL DROP PROCEDURE testProc7
IF OBJECT_ID(N'testProcA', N'P') IS NOT NULL DROP PROCEDURE testProcA
IF OBJECT_ID(N'testProcB', N'P') IS NOT NULL DROP PROCEDURE testProcB
IF OBJECT_ID(N'testProcC', N'P') IS NOT NULL DROP PROCEDURE testProcC
IF OBJECT_ID(N'testProcD', N'P') IS NOT NULL DROP PROCEDURE testProcD
GO

CREATE TABLE testDimDate
(
   DateKey DATE NOT NULL,
   CONSTRAINT PK_DimDate_DateKey UNIQUE NONCLUSTERED (DateKey ASC)
)
GO

DECLARE @dateTimeStart DATETIME = '2000-01-01'
DECLARE @dateTimeEnd DATETIME = '2100-01-01'
;WITH CTE AS
(
   --Anchor member defined
   SELECT @dateTimeStart FullDate
   UNION ALL
   --Recursive member defined referencing CTE
   SELECT FullDate + 1 FROM CTE WHERE FullDate + 1 <= @dateTimeEnd
)
SELECT
   CAST(FullDate AS DATE) AS DateKey
INTO #DimDate
FROM CTE
OPTION (MAXRECURSION 0)

INSERT INTO testDimDate (DateKey)
SELECT DateKey FROM #DimDate ORDER BY DateKey ASC

DROP TABLE #DimDate
GO

-- Hard coded date range.
CREATE PROCEDURE testProc1 AS
BEGIN
   SET NOCOUNT ON
   SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN '2012-12-09' AND '2012-12-10'
END
GO

-- Parameter and variable date range.
CREATE PROCEDURE testProc2(@endDate DATE) AS
BEGIN
   SET NOCOUNT ON
   DECLARE @startDate DATE = DATEADD(DAY, -1, @endDate)
   SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN @startDate AND @endDate
END
GO

-- Parameter date range.
CREATE PROCEDURE testProc3a(@startDate DATE, @endDate DATE) AS
BEGIN
   SET NOCOUNT ON
   SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN @startDate AND @endDate
END
GO

-- Wrapper procedure.
CREATE PROCEDURE testProc3(@endDate DATE) AS
BEGIN
   SET NOCOUNT ON
   DECLARE @startDate DATE = DATEADD(DAY, -1, @endDate)
   EXEC testProc3a @startDate, @endDate
END
GO

-- Parameterized dynamic SQL.
CREATE PROCEDURE testProc4(@endDate DATE) AS
BEGIN
   SET NOCOUNT ON
   DECLARE @startDate DATE = DATEADD(DAY, -1, @endDate)
   DECLARE @sql NVARCHAR(4000) = N'SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN @startDate AND @endDate'
   DECLARE @param NVARCHAR(4000) = N'@startDate DATE, @endDate DATE'
   EXEC sp_executesql @sql, @param, @startDate = @startDate, @endDate = @endDate
END
GO

-- Hard coded dynamic SQL.
CREATE PROCEDURE testProc5(@endDate DATE) AS
BEGIN
   SET NOCOUNT ON
   DECLARE @startDate DATE = DATEADD(DAY, -1, @endDate)
   DECLARE @sql NVARCHAR(4000) = N'SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN ''@startDate'' AND ''@endDate'''
   SET @sql = REPLACE(@sql, '@startDate', CONVERT(NCHAR(10), @startDate, 126))
   SET @sql = REPLACE(@sql, '@endDate', CONVERT(NCHAR(10), @endDate, 126))
   EXEC sp_executesql @sql
END
GO

-- Explicitly use DATEADD on a DATE.
CREATE PROCEDURE testProc6(@endDate DATE) AS
BEGIN
   SET NOCOUNT ON
   SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN DATEADD(DAY, -1, @endDate) AND @endDate
END
GO

-- Dummy parameter.
CREATE PROCEDURE testProc7(@endDate DATE, @startDate DATE = NULL) AS
BEGIN
   SET NOCOUNT ON
   SET @startDate = DATEADD(DAY, -1, @endDate)
   SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN @startDate AND @endDate
END
GO

-- Explicitly use DATEADD on a DATETIME with implicit CAST for comparison with SaleDate.
-- Based on the answer from Mikael Eriksson.
CREATE PROCEDURE testProcA(@endDateTime DATETIME) AS
BEGIN
   SET NOCOUNT ON
   SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN DATEADD(DAY, -1, @endDateTime) AND @endDateTime
END
GO

-- Explicitly use DATEADD on a DATETIME but CAST to DATE for comparison with SaleDate.
-- Based on the answer from Mikael Eriksson.
CREATE PROCEDURE testProcB(@endDateTime DATETIME) AS
BEGIN
   SET NOCOUNT ON
   SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN CAST(DATEADD(DAY, -1, @endDateTime) AS DATE) AND CAST(@endDateTime AS DATE)
END
GO

-- Use a date lookup table, Sale first.
-- Based on the answer from Kenneth Fisher.
CREATE PROCEDURE testProcC(@endDate DATE) AS
BEGIN
   SET NOCOUNT ON
   DECLARE @startDate DATE = DATEADD(DAY, -1, @endDate)
   SELECT SUM(Value) FROM Sale J INNER JOIN testDimDate D ON D.DateKey = J.SaleDate WHERE D.DateKey BETWEEN @startDate AND @endDate
END
GO

-- Use a date lookup table, Sale last.
-- Based on the answer from Kenneth Fisher.
CREATE PROCEDURE testProcD(@endDate DATE) AS
BEGIN
   SET NOCOUNT ON
   DECLARE @startDate DATE = DATEADD(DAY, -1, @endDate)
   SELECT SUM(Value) FROM testDimDate D INNER JOIN Sale J ON J.SaleDate = D.DateKey WHERE D.DateKey BETWEEN @startDate AND @endDate
END
GO

------ TEST ------

SET STATISTICS TIME OFF

DECLARE @endDate DATE = '2012-12-10'
DECLARE @startDate DATE = DATEADD(DAY, -1, @endDate)

DBCC FREEPROCCACHE WITH NO_INFOMSGS
DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS

RAISERROR('Run 1: NoProc with constants', 0, 0) WITH NOWAIT
SET STATISTICS TIME ON
SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN '2012-12-09' AND '2012-12-10'
SET STATISTICS TIME OFF

RAISERROR('Run 2: NoProc with constants', 0, 0) WITH NOWAIT
SET STATISTICS TIME ON
SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN '2012-12-09' AND '2012-12-10'
SET STATISTICS TIME OFF

DBCC FREEPROCCACHE WITH NO_INFOMSGS
DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS

RAISERROR('Run 1: NoProc with variables', 0, 0) WITH NOWAIT
SET STATISTICS TIME ON
SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN @startDate AND @endDate
SET STATISTICS TIME OFF

RAISERROR('Run 2: NoProc with variables', 0, 0) WITH NOWAIT
SET STATISTICS TIME ON
SELECT SUM(Value) FROM Sale WHERE SaleDate BETWEEN @startDate AND @endDate
SET STATISTICS TIME OFF

DECLARE @sql NVARCHAR(4000)

DECLARE _cursor CURSOR LOCAL FAST_FORWARD FOR
   SELECT
      procedures.name,
      procedures.object_id
   FROM sys.procedures
   WHERE procedures.name LIKE 'testProc_'
   ORDER BY procedures.name ASC

OPEN _cursor

DECLARE @name SYSNAME
DECLARE @object_id INT

FETCH NEXT FROM _cursor INTO @name, @object_id
WHILE @@FETCH_STATUS = 0
BEGIN
   SET @sql = CASE (SELECT COUNT(*) FROM sys.parameters WHERE object_id = @object_id)
      WHEN 0 THEN @name
      WHEN 1 THEN @name + ' ''@endDate'''
      WHEN 2 THEN @name + ' ''@startDate'', ''@endDate'''
   END

   SET @sql = REPLACE(@sql, '@name', @name)
   SET @sql = REPLACE(@sql, '@startDate', CONVERT(NVARCHAR(10), @startDate, 126))
   SET @sql = REPLACE(@sql, '@endDate', CONVERT(NVARCHAR(10), @endDate, 126))

   DBCC FREEPROCCACHE WITH NO_INFOMSGS
   DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS

   RAISERROR('Run 1: %s', 0, 0, @sql) WITH NOWAIT
   SET STATISTICS TIME ON
   EXEC sp_executesql @sql
   SET STATISTICS TIME OFF

   RAISERROR('Run 2: %s', 0, 0, @sql) WITH NOWAIT
   SET STATISTICS TIME ON
   EXEC sp_executesql @sql
   SET STATISTICS TIME OFF

   FETCH NEXT FROM _cursor INTO @name, @object_id
END

CLOSE _cursor
DEALLOCATE _cursor

উত্তর:


9

প্যারামিটার স্নিফিং প্রায় সময়ই আপনার বন্ধু এবং আপনার প্রশ্নগুলি লিখতে হবে যাতে এটি ব্যবহার করা যায়। প্যারামিটার স্নিফিং যখন ক্যোয়ারী সংকলিত হয় তখন প্যারামিটারের মানগুলি উপলব্ধ করে আপনার জন্য পরিকল্পনা তৈরি করতে সহায়তা করে। প্যারামিটার স্নিফিংয়ের অন্ধকার দিকটি যখন ক্যোয়ারী সংকলন করার সময় ব্যবহৃত মানগুলি অনুসন্ধানগুলি আসে তার জন্য অনুকূল নয়।

সঞ্চিত পদ্ধতিতে ক্যোয়ারী সংকলিত হয় যখন সঞ্চিত পদ্ধতিটি কার্যকর করা হয়, কোয়েরি কার্যকর করা হয় না তাই এসকিউএল সার্ভারের যে মানগুলি এখানে মোকাবেলা করতে হবে ...

CREATE PROCEDURE WeeklyProc(@endDate DATE)
AS
BEGIN
  DECLARE @startDate DATE = DATEADD(DAY, -6, @endDate)
  SELECT
    -- Stuff
  FROM Sale
  WHERE SaleDate BETWEEN @startDate AND @endDate
END

এর জন্য একটি জ্ঞাত মান @endDateএবং এর জন্য একটি অজানা মান @startDate। এটি এসকিউএল সার্ভারকে @startDateপরিসংখ্যান যা বলবে তার সাথে মিলিয়ে ফিল্টারটির জন্য ফিরে আসা 30% সারিগুলির অনুমান করতে ছাড়বে @endDate। আপনার যদি প্রচুর সারি সহ একটি বড় টেবিল থাকে যা আপনাকে স্ক্যান অপারেশন দিতে পারে যেখানে আপনি সন্ধান থেকে সবচেয়ে বেশি উপকৃত হবেন।

তোমার মোড়কের পদ্ধতি সমাধান নিশ্চিত করুন যে SQL সার্ভার যখন মান সূচিত তোলে DateRangeProcতাই এটি উভয় জন্য পরিচিত মান ব্যবহার করতে পারেন কম্পাইল করা হয় @endDateএবং @startDate

আপনার গতিশীল প্রশ্নের উভয়ই একই জিনিসকে নিয়ে যায়, মানগুলি সংকলন-সময়ে জানা যায়।

ডিফল্ট নাল মান সহ একটিটি কিছু বিশেষ। সংকলন সময়ে এসকিউএল সার্ভারে পরিচিত মানগুলি এর জন্য @endDateএবং এর nullজন্য একটি জ্ঞাত মান @startDate। এর nullমধ্যে একটি ব্যবহার আপনাকে 0 টি সারি দেবে তবে এসকিউএল সার্ভার সর্বদা অনুমান করে যে 1 ক্ষেত্রে। এটি এক্ষেত্রে ভাল জিনিস হতে পারে তবে আপনি যদি একটি বৃহত তারিখের ব্যবধান সহ সঞ্চিত প্রক্রিয়াটিকে কল করেন যেখানে কোনও স্ক্যানই সেরা পছন্দ হয়ে উঠত এটি একগুচ্ছ চেষ্টা করে শেষ করতে পারে।

আমি এই উত্তরটির শেষে "DATEADD () ফাংশনটি সরাসরি ব্যবহার করুন" রেখেছি কারণ এটিই আমি ব্যবহার করব এবং এটির সাথে এটির মধ্যেও অদ্ভুত কিছু রয়েছে।

প্রথমে, এসকিউএল সার্ভার যখন ফাংশনটি যেখানে ক্লজটিতে ব্যবহৃত হয় তখন একাধিকবার কল করে না। DATEADD রানটাইম ধ্রুবক হিসাবে বিবেচিত হয়

আর আমি যে মনে হবে DATEADDযখন কোয়েরি তাই কম্পাইল করা হয় যে, তোমরা প্রত্যাবর্তিত সারির সংখ্যা একটি ভাল অনুমান পেতে হবে মূল্যায়ন করা হয়। তবে এক্ষেত্রে তেমনটি হয় না।
আপনার সাথে DATEADD(এসকিউএল সার্ভার ২০১২-তে পরীক্ষা করা) নির্বিশেষে প্যারামিটারের মানের উপর ভিত্তি করে এসকিউএল সার্ভারের অনুমান, যাতে আপনার ক্ষেত্রে অনুমানটি নিবন্ধভুক্ত সারিগুলির সংখ্যা হবে @endDate। এটি কেন করে যা আমি জানি না তবে এটি ডেটাটাইপ ব্যবহারের সাথে সম্পর্কিত DATE। Shift ধরে থাকুন DATETIMEসঞ্চিত পদ্ধতি এবং টেবিল এবং অনুমান সঠিক হতে হবে, যার মানে হল DATEADDজন্য কম্পাইল সময়ে বিবেচনা করা হয় DATETIMEনা DATE

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

পুনশ্চ:

মন্তব্যে আপনি দুটি পরামর্শ পেয়েছেন।

OPTION (OPTIMIZE FOR UNKNOWN)আপনাকে পুনরায় 9% সারির পূর্বাভাস OPTION (RECOMPILE)দেবে এবং এসকিউএল সার্ভারকে প্যারামিটারের মানগুলি দেখাবে যেহেতু প্রতিবার কোয়েরিটি পুনরায় সংযুক্ত করা হয়েছে।


3

ঠিক আছে, আপনার জন্য আমার দুটি সম্ভাব্য সমাধান রয়েছে।

প্রথমে আমি ভাবছি যে এটি প্যারামিটারাইজেশন বৃদ্ধি করার অনুমতি দেয় কিনা। আমি এটি পরীক্ষা করার সুযোগ পাইনি তবে এটি কার্যকর হতে পারে।

CREATE PROCEDURE WeeklyProc(@endDate DATE, @startDate DATE)
AS
BEGIN
  IF @startDate IS NULL
    SET @startDate = DATEADD(DAY, -6, @endDate)
  SELECT
    -- Stuff
  FROM Sale
  WHERE SaleDate BETWEEN @startDate AND @endDate
END

অন্য বিকল্পটি আপনি নির্দিষ্ট সময় ফ্রেম ব্যবহার করছেন এমনটির সুযোগ নেয়। প্রথমে একটি ডেটলুকআপ টেবিল তৈরি করুন। এটার মতো কিছু

CurrentDate    8WeekStartDate    8WeekEndDate    etc

এখন এবং পরবর্তী শতাব্দীর মধ্যে প্রতিটি তারিখের জন্য এটি পূরণ করুন। এটি কেবলমাত্র 36500 ডলার সারি তাই মোটামুটি ছোট টেবিল। তারপরে আপনার ক্যোয়ারীটি এভাবে পরিবর্তন করুন

IF @Range = '8WeekRange' 
    SELECT
      -- Stuff
    FROM Sale
    JOIN DateLookup
        ON SaleDate BETWEEN [8WeekStartDate] AND [8WeekEndDate]
    WHERE DateLookup.CurrentDate = GetDate()

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

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