ক্যোয়ারী অপ্টিমাইজেশন: সময়ের ব্যবধান


10

মূলত, আমি দুই ধরণের সময়ের ব্যবধান পেয়েছি:

presence time এবং absence time

absence time বিভিন্ন ধরণের (যেমন বিরতি, অনুপস্থিতি, বিশেষ দিন এবং তাই) হতে পারে এবং সময়ের ব্যবধানগুলি ওভারল্যাপ এবং / বা ছেদ করতে পারে।

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

;with "timestamps"
as
(
    select
        "id" = row_number() over ( order by "empId", "timestamp", "opening", "type" )
        , "empId"
        , "timestamp"
        , "type"
        , "opening"
    from
    (
        select "empId", "timestamp", "type", case when "types" = 'starttime' then 1 else -1 end as "opening" from
        ( select "empId", "starttime", "endtime", 1 as "type" from "worktime" ) as data
        unpivot ( "timestamp" for "types" in ( "starttime", "endtime" ) ) as pvt
        union all
        select "empId", "timestamp", "type", case when "types" = 'starttime' then 1 else -1 end as "opening" from
        ( select "empId", "starttime", "endtime", 2 as "type" from "break" ) as data
        unpivot ( "timestamp" for "types" in ( "starttime", "endtime" ) ) as pvt
        union all
        select "empId", "timestamp", "type", case when "types" = 'starttime' then 1 else -1 end as "opening" from
        ( select "empId", "starttime", "endtime", 3 as "type" from "absence" ) as data
        unpivot ( "timestamp" for "types" in ( "starttime", "endtime" ) ) as pvt
    ) as data
)
select 
      T1."empId"
    , "starttime"   = T1."timestamp"
    , "endtime"     = T2."timestamp"
from 
    "timestamps" as T1
    left join "timestamps" as T2
        on T2."empId" = T1."empId"
        and T2."id" = T1."id" + 1
    left join "timestamps" as RS
        on RS."empId" = T2."empId"
        and RS."id" <= T1."id"      
group by
    T1."empId", T1."timestamp", T2."timestamp"
having
    (sum( power( 2, RS."type" ) * RS."opening" ) = 2)
order by 
    T1."empId", T1."timestamp";

কিছু ডেমো ডেটার জন্য এসকিউএল-ফিডল দেখুন ।

কাঁচা ডেটা বিভিন্ন আকারে "starttime" - "endtime"বা আকারে বিদ্যমান "starttime" - "duration"

উপস্থিতির সময়টি অনুমান করার জন্য প্রতিটি সময়ে "বিটমাস্কড" রোলিং সমষ্টি সহ প্রতিটি টাইমস্ট্যাম্পের একটি অর্ডারযুক্ত তালিকা পাওয়ার ধারণা ছিল।

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

এটি কি প্রশ্নযুক্ত কার্য অর্জনের সঠিক উপায় বা এর জন্য আরও মার্জিত কোনও উপায় আছে?

যদি উত্তর দেওয়ার জন্য প্রাসঙ্গিক হয়: তথ্যের পরিমাণ প্রতি টেবিল প্রতি কর্মচারী বেশ কয়েক দশ-হাজার ডেটাসেট পর্যন্ত হবে। সামগ্রিকভাবে ইনলাইন পূর্বসূরীদের রোলিং যোগফল গণনা করার জন্য স্কুয়েল -২০১২ উপলভ্য নয়।


সম্পাদনা:

সর্বাধিক পরিমাণ টেস্টডাটা (1000, 10.000, 100.000, 1 মিলিয়ন) এর বিপরীতে ক্যোয়ারী কার্যকর করা হয়েছে এবং রানটাইমটি তাত্পর্যপূর্ণভাবে বৃদ্ধি পায় তা দেখতে পাবে। স্পষ্টতই একটি সতর্কতা পতাকা, ডান?

আমি কোয়েরিটি পরিবর্তন করেছি এবং একটি উদ্দীপক আপডেটের মাধ্যমে রোলিংয়ের সমষ্টিকে সরিয়েছি।

আমি একটি সহায়ক টেবিল যুক্ত করেছি:

create table timestamps
(
  "id" int
  , "empId" int
  , "timestamp" datetime
  , "type" int
  , "opening" int
  , "rolSum" int
)

create nonclustered index "idx" on "timestamps" ( "rolSum" ) include ( "id", "empId", "timestamp" )

এবং আমি এই স্থানটিতে রোলিংয়ের যোগফল গণনা করেছি:

declare @rolSum int = 0
update "timestamps" set @rolSum = "rolSum" = @rolSum + power( 2, "type" ) * "opening" from "timestamps"

এসকিউএল-ফিডল এখানে দেখুন

"ওয়ার্কটাইম"-টেবিলের 1 মিলিয়ন এন্ট্রি সম্পর্কিত রানটাইম হ্রাস পেয়ে 3 সেকেন্ডে দাঁড়িয়েছে।

প্রশ্ন একই থাকে : এটি সমাধানের সবচেয়ে কার্যকর উপায় কী?


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

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

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

আমার বিশ্বের @Nico যা সাধারণত মত তারপর বর্গাকার বন্ধনী সঙ্গে সম্পন্ন [this]। আমার মনে হয় ডাবল উক্তিগুলির চেয়ে এটি আরও ভাল।
এরিক

@ এরিক স্কোয়ার বন্ধনী tsql। স্ট্যান্ডার্ড ডাবল কোট! যাইহোক, আমি এটি সেভাবে শিখেছি এবং তাই কোনওভাবে এটি অভ্যস্ত!
নিকো

উত্তর:


3

আমি আপনার প্রশ্নের একেবারে সেরা উপায় হিসাবে উত্তর দিতে পারে না। তবে আমি সমস্যাটি সমাধানের জন্য একটি ভিন্ন উপায়ে প্রস্তাব করতে পারি , যা ভাল বা নাও হতে পারে। এটিতে যুক্তিসঙ্গতভাবে সমতল সম্পাদনের পরিকল্পনা রয়েছে এবং আমি মনে করি এটি ভাল प्रदर्शन করবে। (আমি ফলাফল জানতে তাই আগ্রহী!)

আমি আপনার পরিবর্তে আমার নিজস্ব সিনট্যাক্স শৈলী ব্যবহারের জন্য ক্ষমাপ্রার্থী - সবকিছু উইন্ডো যখন স্বাভাবিক স্থানে সরে যায় তখন কোয়েরি উইজার্ড্রিকে আমার কাছে আসতে সহায়তা করে।

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

WITH Points AS (
  SELECT DISTINCT
    T.EmpID,
    P.TimePoint
  FROM
    (
      SELECT * FROM dbo.WorkTime
      UNION SELECT * FROM dbo.BreakTime
      UNION SELECT * FROM dbo.Absence
    ) T
    CROSS APPLY (VALUES (StartTime), (EndTime)) P (TimePoint)
), Groups AS (
  SELECT
    P.EmpID,
    P.TimePoint,
    Grp =
      Row_Number()
      OVER (PARTITION BY P.EmpID ORDER BY P.TimePoint, X.Which) / 2
  FROM
    Points P
    CROSS JOIN (VALUES (1), (2)) X (Which)
), Ranges AS (
  SELECT
    G.EmpID,
    StartTime = Min(G.TimePoint),
    EndTime = Max(G.TimePoint)
  FROM Groups G
  GROUP BY
    G.EmpID,
    G.Grp
  HAVING Count(*) = 2
), Presences AS (
  SELECT
    R.*,
    P.Present,
    Grp =
       Dense_Rank() OVER (PARTITION BY R.EmpID ORDER BY R.StartTime)
       - Dense_Rank() OVER (PARTITION BY R.EmpID, P.Present ORDER BY R.StartTime)
  FROM
    Ranges R
    CROSS APPLY (
      SELECT
        CASE WHEN EXISTS (
          SELECT *
          FROM dbo.WorkTime W
          WHERE
            R.EmpID = W.EmpID
            AND R.StartTime < W.EndTime
            AND W.StartTime < R.EndTime
        ) AND NOT EXISTS (
          SELECT *
          FROM dbo.BreakTime B
          WHERE
            R.EmpID = B.EmpID
            AND R.StartTime < B.EndTime
            AND B.StartTime < R.EndTime
        ) AND NOT EXISTS (
          SELECT *
          FROM dbo.Absence A
          WHERE
            R.EmpID = A.EmpID
            AND R.StartTime < A.EndTime
            AND A.StartTime < R.EndTime
        ) THEN 1 ELSE 0 END
    ) P (Present)
)
SELECT
  EmpID,
  StartTime = Min(StartTime),
  EndTime = Max(EndTime)
FROM Presences
WHERE Present = 1
GROUP BY
  EmpID,
  Grp
ORDER BY
  EmpID,
  StartTime;

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

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

এখন আমি যাচ্ছি এবং দেখুন আমি এটি সম্পাদন করার জন্য অন্য কৌশলটি ভাবতে পারি না কিনা। :)

বিনোদনের জন্য আমি এখানে একটি "চিত্র" অন্তর্ভুক্ত করেছি যা সমস্যার সমাধান করতে সহায়তা করে:

------------
   -----------------
                ---------------
                           -----------

    ---    ------   ------       ------------

----   ----      ---      -------

ড্যাশগুলির তিনটি সেট (স্পেস দ্বারা বিচ্ছিন্ন) প্রতিনিধিত্ব করে, যাতে: উপস্থিতি তথ্য, অনুপস্থিতি ডেটা এবং পছন্দসই ফলাফল।


এই পদ্ধতির জন্য ধন্যবাদ। আমি অফিসে ফিরে আসার সময় এটি পরীক্ষা করে দেখব এবং বৃহত্তর ডেটা-বেসের সাথে রানটাইম-ফলাফল দেব।
নিকো

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

আমার আর একটি ধারণা আছে আমি কাজ করার জন্য সময় পাইনি। এটি মূল্যবান কিসের জন্য, আপনার ক্যোয়ারী সমস্ত টেবিলের ওভারল্যাপিং রেঞ্জগুলির সাথে ভুল ফলাফল দেয় returns
এরিক

আমি এটি আবার পরীক্ষা করে দেখলাম, এই তিনটি টেবিলের মধ্যে সম্পূর্ণরূপে ওভারল্যাপিং অন্তরগুলি রয়েছে এমন এই ফ্রিডলটি দেখুন । এটি দেখতে সঠিক ফলাফলগুলি দেয়। আপনি কি এমন কোনও মামলা দিতে পারেন যাতে ভুল ফলাফলগুলি ফিরে আসে? ডিমো ডেটা ডেটা অ্যাডজল করতে নির্দ্বিধায়!
নিকো

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