একটি ডেটটাইম মান (এসকিউএল সার্ভার) এর সময়ের অংশটি কীভাবে সরিয়ে ফেলবেন?


85

আমি যা ব্যবহার করি তা এখানে:

SELECT CAST(FLOOR(CAST(getdate() as FLOAT)) as DATETIME)

আমি ভাবছি এর চেয়ে ভাল এবং আরও মার্জিত উপায় হতে পারে।

প্রয়োজনীয়তা:

  • এটি যতটা সম্ভব দ্রুত হওয়া উচিত (যত কম কাস্টিং, তত ভাল)।
  • চূড়ান্ত ফলাফলটি datetimeস্ট্রিং নয়, একটি ধরণের হতে হবে ।

উত্তর:


116

এসকিউএল সার্ভার ২০০৮ এবং তার বেশি

এসকিউএল সার্ভার ২০০৮ এবং তারপরে অবশ্যই সবচেয়ে দ্রুততম উপায় Convert(date, @date)। এটি একটি datetimeবা datetime2প্রয়োজনে আবার কাস্ট করা যেতে পারে ।

এসকিউএল সার্ভার ২০০৫ এবং এর থেকেও পুরনো ক্ষেত্রে সত্যিই সেরা কী?

এসকিউএল সার্ভারে একটি তারিখ থেকে সময় কেটে নেওয়ার জন্য দ্রুততম সম্পর্কে কী অসঙ্গত দাবিগুলি দেখেছি এবং কিছু লোক এমনকি তারা বলেছিল যে তারা পরীক্ষা করেছে তবে আমার অভিজ্ঞতাটি অন্যরকম হয়েছে। সুতরাং আসুন আমরা আরও কিছু কঠোর পরীক্ষা করি এবং প্রত্যেকের কাছে স্ক্রিপ্ট থাকি যাতে আমি যদি কোনও ভুল করি তবে লোকেরা আমাকে সংশোধন করতে পারে।

ফ্লোট রূপান্তরগুলি সঠিক নয়

প্রথমত, আমি রূপান্তর datetimeকরা থেকে দূরে থাকব float, কারণ এটি সঠিকভাবে রূপান্তর করে না। আপনি সঠিকভাবে সময় অপসারণ জিনিস সঙ্গে কাজ পেতে পারে, কিন্তু আমি মনে করি এটা একটি খারাপ ধারণা করা হয়েছে কারণ এটি পরোক্ষভাবে বিকাশকারীদের কাছে যোগাযোগ করে যে এই একটি নিরাপদ অপারেশন হয় এবং এটি ব্যবহার করবেন তা তা না হয় । এক নজর দেখে নাও:

declare @d datetime;
set @d = '2010-09-12 00:00:00.003';
select Convert(datetime, Convert(float, @d));
-- result: 2010-09-12 00:00:00.000 -- oops

এটি আমাদের কোড বা আমাদের উদাহরণগুলিতে লোকদের শেখানো উচিত এমন কিছু নয়।

এছাড়াও, এটি এমনকি দ্রুততম উপায়ও নয়!

প্রুফ - পারফরম্যান্স টেস্টিং

বিভিন্ন পদ্ধতি কীভাবে সত্যিই সজ্জিত হয় তা দেখতে আপনি যদি কিছু পরীক্ষা নিজেই করতে চান তবে পরীক্ষা আরও দূরে চালানোর জন্য আপনার এই সেটআপ স্ক্রিপ্টের প্রয়োজন হবে:

create table AllDay (Tm datetime NOT NULL CONSTRAINT PK_AllDay PRIMARY KEY CLUSTERED);
declare @d datetime;
set @d = DateDiff(Day, 0, GetDate());
insert AllDay select @d;
while @@ROWCOUNT != 0
   insert AllDay
   select * from (
      select Tm =
         DateAdd(ms, (select Max(DateDiff(ms, @d, Tm)) from AllDay) + 3, Tm)
      from AllDay
   ) X
   where Tm < DateAdd(Day, 1, @d);
exec sp_spaceused AllDay;  -- 25,920,000 rows

দয়া করে নোট করুন যে এটি আপনার ডাটাবেসে একটি 427.57 মেগাবাইট সারণী তৈরি করে এবং এটি চালাতে 15-30 মিনিটের মতো কিছু লাগবে। আপনার ডাটাবেস যদি ছোট হয় এবং 10% প্রবৃদ্ধিতে সেট করা থাকে তবে আপনি যদি প্রথমে যথেষ্ট বড় আকারের হন তবে এটি বেশি সময় নেয়।

এখন প্রকৃত কর্মক্ষমতা পরীক্ষার স্ক্রিপ্টের জন্য। দয়া করে মনে রাখবেন যে ক্লায়েন্টের কাছে সারিগুলি ফিরিয়ে না দেওয়া উদ্দেশ্যমূলক কারণ এটি 26 মিলিয়ন সারিগুলিতে ব্যয়বহুল এবং পদ্ধতিগুলির মধ্যে পারফরম্যান্সের পার্থক্যগুলি লুকিয়ে রাখে।

কর্মক্ষমতা ফলাফল

set statistics time on;
-- (All queries are the same on io: logical reads 54712)
GO
declare
    @dd date,
    @d datetime,
    @di int,
    @df float,
    @dv varchar(10);

-- Round trip back to datetime
select @d = CONVERT(date, Tm) from AllDay; -- CPU time = 21234 ms,  elapsed time = 22301 ms.
select @d = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 23031 ms, elapsed = 24091 ms.
select @d = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23782 ms, elapsed = 24818 ms.
select @d = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 36891 ms, elapsed = 38414 ms.
select @d = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 102984 ms, elapsed = 109897 ms.
select @d = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 103390 ms,  elapsed = 108236 ms.
select @d = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 123375 ms, elapsed = 135179 ms.

-- Only to another type but not back
select @dd = Tm from AllDay; -- CPU time = 19891 ms,  elapsed time = 20937 ms.
select @di = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 21453 ms, elapsed = 23079 ms.
select @di = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23218 ms, elapsed = 24700 ms
select @df = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 29312 ms, elapsed = 31101 ms.
select @dv = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 64016 ms, elapsed = 67815 ms.
select @dv = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 64297 ms,  elapsed = 67987 ms.
select @dv = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 65609 ms, elapsed = 68173 ms.
GO
set statistics time off;

কিছু র‌্যাম্বলিং বিশ্লেষণ

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

select Convert(datetime, DateDiff(dd, 0, Tm))
from (select '2010-09-12 00:00:00.003') X (Tm)
group by DateDiff(dd, 0, Tm)

এছাড়াও, দেখুন কীভাবে সংখ্যার রূপান্তরগুলি পুনরায় রূপান্তর করতে কেবল আরও কিছুটা সময় নেয় datetime, তবেvarchar রূপান্তরটি প্রায় দ্বিগুণ হয়? এটি সিপিইউর অংশটি প্রকাশ করে যা কোয়েরিতে তারিখ গণনার জন্য উত্সর্গীকৃত। সিপিইউ ব্যবহারের কিছু অংশ রয়েছে যা তারিখ গণনা জড়িত না এবং এটি উপরের প্রশ্নের মধ্যে 19875 এমএসের কাছাকাছি কিছু বলে মনে হচ্ছে। তারপরে রূপান্তরটি কিছু অতিরিক্ত পরিমাণ নেয়, সুতরাং যদি দুটি রূপান্তর হয় তবে সেই পরিমাণটি প্রায় দ্বিগুণ ব্যবহৃত হয়।

আরও পরীক্ষা করে দেখা যায় যে তুলনায় Convert(, 112), Convert(, 101)ক্যোয়ারিতে কিছু অতিরিক্ত সিপিইউ ব্যয় হয়েছে (যেহেতু এটি দীর্ঘ ব্যবহার করে varchar?), কারণ দ্বিতীয় রূপান্তরটি dateপ্রাথমিক রূপান্তর হিসাবে তত বেশি ব্যয় করে না varchar, তবে Convert(, 112)এটি একই 20000 এর কাছাকাছি রয়েছে এমএস সিপিইউ বেস ব্যয়।

আমি উপরের বিশ্লেষণের জন্য সিপিইউ সময়ে সেই গণনাগুলি ব্যবহার করেছি:

     method   round  single   base
-----------  ------  ------  -----
       date   21324   19891  18458
        int   23031   21453  19875
   datediff   23782   23218  22654
      float   36891   29312  21733
varchar-112  102984   64016  25048
varchar-101  123375   65609   7843
  • রাউন্ডটি ফিরে আসার জন্য রাউন্ড ট্রিপের সিপিইউ সময় datetime

  • একক হ'ল সিপিইউ সময় হ'ল একক রূপান্তর করার জন্য বিকল্প ডেটা টাইপ (সময় অংশ অপসারণের পার্শ্ব প্রতিক্রিয়া রয়েছে এমন এক)।

  • বেস থেকে বিয়োগ হিসাব হয় singleদুই আমন্ত্রণ মধ্যে পার্থক্য: single - (round - single)। এটি একটি বলপার্ক চিত্র যা এই ডেটা টাইপ এবং datetimeএ থেকে রূপান্তর অনুমান করে এবং উভয় দিক থেকেই প্রায় একই। এটি প্রদর্শিত হয় এই অনুমানটি নিখুঁত নয় তবে নিকটে কারণ মানগুলি কেবলমাত্র একটি ব্যতিক্রম সহ 20000 এমএসের নিকটে।

আরও একটি আকর্ষণীয় বিষয় হ'ল বেস ব্যয়টি একক Convert(date)পদ্ধতির প্রায় সমান (যা প্রায় 0 ব্যয় হতে হবে, কারণ সার্ভারটি অভ্যন্তরীণভাবে datetimeডেটা টাইপের প্রথম চারটি বাইটের মধ্যে পূর্ণসংখ্যার দিনের অংশটি বের করতে পারে )।

উপসংহার

সুতরাং এটি দেখতে যা দেখায় তা হ'ল একক দিকের varcharরূপান্তর পদ্ধতিটি প্রায় 1.8 takes সেবন করে এবং একক দিকের DateDiffপদ্ধতিটি প্রায় 0.18 takes সেবন করে। আমি 18458 এমএস মোট 25,920,000 সারির জন্য আমার পরীক্ষার সময় সবচেয়ে রক্ষণশীল "বেস সিপিইউ" এর উপর ভিত্তি করে চলেছি, সুতরাং 23218 এমএস / 25920000 = 0.18। সে। আপাত 10x এর উন্নতি অনেকটা মনে হয় তবে আপনি কয়েক হাজার সারি (617k সারি = 1 সেকেন্ডের সঞ্চয়) নিয়ে কাজ না করা অবধি এটি খুব সুন্দর small

এমনকি এই ক্ষুদ্র পরম উন্নতি দেওয়া, আমার মতে, DateAddপদ্ধতিটি জিতেছে কারণ এটি কার্য সম্পাদন এবং স্পষ্টতার সর্বোত্তম সমন্বয়। যেটির "ম্যাজিক নম্বর" এর উত্তর প্রয়োজন 0.50000004তা কোনও দিন কাউকে কামড়ায় (পাঁচটি শূন্য বা ছয় ???), এবং এটি বোঝা আরও শক্ত।

অতিরিক্ত নোট

আমি যখন কিছুটা সময় পাই তখন আমি পরিবর্তন 0.50000004করতে যাব '12:00:00.003'এবং এটি কীভাবে হয় তা দেখুন। এটি একই datetimeমানতে রূপান্তরিত হয়েছে এবং আমি মনে রাখা এটি আরও সহজ মনে করি।

আগ্রহীদের জন্য, উপরোক্ত পরীক্ষাগুলি এমন একটি সার্ভারে চালানো হয়েছিল যেখানে @@ সংস্করণটি নিম্নলিখিতগুলি প্রদান করে:

মাইক্রোসফ্ট এসকিউএল সার্ভার ২০০৮ (আরটিএম) - 10.0.1600.22 (ইন্টেল এক্স 86) জুলাই 9 2008 14:43:34 কপিরাইট (সি) 1988-2008 উইন্ডোজ এনটি 5.2 তে মাইক্রোসফ্ট কর্পোরেশন স্ট্যান্ডার্ড সংস্করণ (বিল্ড 3790: সার্ভিস প্যাক 2)


4
+1 এসকিউএল সার্ভারের কোন সংস্করণ আপনি এটি দিয়ে পরীক্ষা করেছেন?
মার্টিন স্মিথ

4
দেখে মনে হচ্ছে আপনার টেবিলে আপনার একা এবং গোলাকার পিছনের দিক রয়েছে। এছাড়াও, যদি আপনি charপরিবর্তে ব্যবহার করেন তবে কি সময়ের মধ্যে কোনও পার্থক্য রয়েছে varchar?
গ্যাবে

4
@ গ্যাব ধন্যবাদ, স্থির। চরটি ঠিক একইভাবে বর্ণের মতো দেখা যায়।
এরিক

ওরাকল এ আছে select round(sysdate) from dualএবং আমাদের অবশ্যই এটি এসকিএল সার্ভারে দরকার।
ডেনিস ভালেভ

4
@ রোমন আপনি যদি এসকিউএল সার্ভার ২০০৮ এবং এর সাথে কাজ করছেন তবে হ্যাঁ, dateউপাত্তের পরীক্ষায় যেমন দেখানো হয়েছে তেমনি ডেটা টাইপে রূপান্তর করা দ্রুততম।
এরিক

30

এসকিউএল সার্ভার ২০০৮-এ একটি নতুন তারিখের ডেটা টাইপ রয়েছে এবং এটি এই সমস্যাটিকে এটিকে সহজতর করে:

SELECT CAST(CAST(GETDATE() AS date) AS datetime)

4
আমি বছর হিসাবে 2018 এর পরিবর্তে 0218 এর পরিবর্তে প্রবেশ করেছি এবং DATEADD(DATEDIFF())সময়ের অংশটি কাটা করার পদ্ধতিটি একটি ব্যতিক্রম ছুঁড়েছে। যখন আমি ফলাফলটি datetime2আপনার পদ্ধতিতে ফিরিয়ে ফেলি তখন দুর্দান্তভাবে কাজ করেselect cast(CAST(convert(datetime2(0), '0218-09-12', 120) AS date) as datetime2)
বার্নহার্ড ডাবলার

18

ডেটটাইম গণনাগুলিতে ইটজিক বেন-গান , পার্ট 1 (এসকিউএল সার্ভার ম্যাগাজিন, ফেব্রুয়ারী 2007) এ জাতীয় রূপান্তর সম্পাদনের তিনটি পদ্ধতি দেখায় ( দ্রুত থেকে ধীরতম ; দ্বিতীয় এবং তৃতীয় পদ্ধতির মধ্যে পার্থক্য কম):

SELECT CAST(CONVERT(char(8), GETDATE(), 112) AS datetime)

SELECT DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)

SELECT CAST(CAST(GETDATE() - 0.50000004 AS int) AS datetime)

আপনার কৌশলটি (ভাসমানের কাছে ingালাই ) ম্যাগাজিনের এপ্রিল সংখ্যায় একটি পাঠক পরামর্শ দিয়েছেন। তাঁর মতে, এটি উপস্থাপিত দ্বিতীয় কৌশলটির সাথে তুলনীয় পারফরম্যান্স রয়েছে।


4
আমার মতে ভাসতে কাস্টিং সেরা নয়। দয়া করে আমার উত্তরটি দেখুন
এরিক

4
@Emtucifor সে ব্যাপারে আমি সম্মত 3rd পদ্ধতি খুব কারণে অস্পষ্ট হয় 0,50000004 মান, কিন্তু এটা দ্রুততম এক এবং আপনার পরীক্ষার যে নিশ্চিত । সুতরাং, এটি যত তাড়াতাড়ি সম্ভব প্রয়োজনীয়তাকে সন্তুষ্ট করে ।
মারেক গ্রাজেনকোভিজ

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

4
যদি আমরা এই পদ্ধতিটি ব্যবহার করতে যাচ্ছি তবে আমি তার SELECT CAST(CAST(GETDATE() - '12:00:00.003' AS int) AS datetime)পরিবর্তে পছন্দ করব , কারণ এটি আমার কাছে কিছু অর্থ এবং স্মরণে রাখা খুব সহজ।
এরিক

6
এটি এখন দ্রুততম এসকিউএল 2008 সালে হল: Convert(date, GetDate())
এরিক

12

তোমার CAST- FLOOR- CASTইতিমধ্যে অন্তত মাইক্রোসফট SQL সার্ভার 2005, সর্বোত্তম পথ বলে মনে হয়।

আমি দেখেছি এমন আরও কয়েকটি সমাধানগুলির মধ্যে স্ট্রিং-রূপান্তর রয়েছে Select Convert(varchar(11), getdate(),101), যা 10 এর ফ্যাক্টর দ্বারা ধীর।


4
আমরা আমাদের পণ্যগুলির মধ্যে মাইকেল স্টামের প্রস্তাবিত পদ্ধতিটি ব্যবহার করি এবং এটি একটি কবজির মতো কাজ করে।
ক্রিস রবার্টস

4
কিছুটা হলেও এটি সর্বোত্তম উপায় নয়। আমার উত্তরটি একই পৃষ্ঠায় দেখুন দয়া করে ।
এরিক


1

এসকিউএল ২০০৫: আমি ডেটড্যাডের পরিবর্তে কাস্ট করার পরামর্শ দিই। উদাহরণ স্বরূপ,

select cast(DATEDIFF(DAY, 0, datetimefield) as datetime)

এর চেয়ে আমার ডেটাসেটে গড়ে প্রায় 10% দ্রুতগতি হয়

select DATEADD(DAY, DATEDIFF(DAY, 0, datetimefield), 0)

(এবং স্মার্টডেটটাইমে কাস্টিং আরও দ্রুত ছিল)

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