Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Bagaimana cara menghapus bagian waktu dari nilai datetime (SQL Server)?

SQL Server 2008 dan yang lebih baru

Di SQL Server 2008 dan yang lebih baru, tentu saja cara tercepat adalah Convert(date, @date) . Ini dapat dilemparkan kembali ke datetime atau datetime2 jika perlu.

Apa yang Benar-Benar Terbaik di SQL Server 2005 dan yang Lebih Lama?

Saya telah melihat klaim yang tidak konsisten tentang apa yang tercepat untuk memotong waktu dari tanggal di SQL Server, dan beberapa orang bahkan mengatakan mereka melakukan pengujian, tetapi pengalaman saya berbeda. Jadi mari kita lakukan pengujian yang lebih ketat dan biarkan semua orang memiliki skripnya sehingga jika saya membuat kesalahan, orang-orang dapat mengoreksi saya.

Konversi Mengambang Tidak Akurat

Pertama, saya akan menghindari konversi datetime untuk float , karena tidak mengonversi dengan benar. Anda mungkin lolos dengan melakukan penghapusan waktu secara akurat, tetapi saya pikir itu adalah ide yang buruk untuk menggunakannya karena secara implisit berkomunikasi dengan pengembang bahwa ini adalah operasi yang aman dan tidak . Lihat:

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

Ini bukanlah sesuatu yang harus kita ajarkan kepada orang-orang dalam kode kita atau dalam contoh kita secara online.

Juga, ini bahkan bukan cara tercepat!

Bukti – Pengujian Kinerja

Jika Anda ingin melakukan beberapa pengujian sendiri untuk melihat bagaimana metode yang berbeda benar-benar ditumpuk, maka Anda memerlukan skrip penyiapan ini untuk menjalankan pengujian lebih jauh ke bawah:

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

Harap perhatikan bahwa ini membuat tabel 427,57 MB di database Anda dan akan memakan waktu sekitar 15-30 menit untuk dijalankan. Jika basis data Anda kecil dan disetel ke pertumbuhan 10%, ini akan memakan waktu lebih lama daripada jika Anda berukuran cukup besar terlebih dahulu.

Sekarang untuk skrip pengujian kinerja yang sebenarnya. Harap dicatat bahwa ini bertujuan untuk tidak mengembalikan baris ke klien karena ini sangat mahal pada 26 juta baris dan akan menyembunyikan perbedaan kinerja antara metode.

Hasil Kinerja

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;

Beberapa Analisis Bertele-tele

Beberapa catatan tentang ini. Pertama-tama, jika hanya melakukan GROUP BY atau perbandingan, tidak perlu mengonversi kembali ke datetime . Jadi Anda dapat menghemat beberapa CPU dengan menghindarinya, kecuali jika Anda memerlukan nilai akhir untuk tujuan tampilan. Anda bahkan dapat mengelompokkan menurut nilai yang belum dikonversi dan menempatkan konversi hanya dalam klausa SELECT:

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

Juga, lihat bagaimana konversi numerik hanya membutuhkan sedikit lebih banyak waktu untuk mengkonversi kembali ke datetime , tetapi varchar konversi hampir dua kali lipat? Ini mengungkapkan bagian CPU yang dikhususkan untuk perhitungan tanggal dalam kueri. Ada bagian dari penggunaan CPU yang tidak melibatkan penghitungan tanggal, dan ini tampaknya mendekati 19875 md dalam kueri di atas. Kemudian konversi tersebut membutuhkan jumlah tambahan, jadi jika ada dua konversi, jumlah tersebut habis kira-kira dua kali.

Pemeriksaan lebih lanjut mengungkapkan bahwa dibandingkan dengan Convert(, 112) , Convert(, 101) kueri memiliki beberapa pengeluaran CPU tambahan (karena menggunakan varchar yang lebih panjang ?), karena konversi kedua kembali ke date tidak memerlukan biaya sebesar konversi awal ke varchar , tetapi dengan Convert(, 112) ini mendekati biaya dasar CPU 20000 md yang sama.

Berikut adalah perhitungan waktu CPU yang saya gunakan untuk analisis di atas:

     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
  • putaran adalah waktu CPU untuk perjalanan pulang pergi ke datetime .

  • lajang adalah waktu CPU untuk satu konversi ke tipe data alternatif (salah satu yang memiliki efek samping menghapus porsi waktu).

  • dasar adalah perhitungan pengurangan dari single perbedaan antara dua pemanggilan:single - (round - single) . Ini adalah angka rata-rata yang mengasumsikan konversi ke dan dari tipe data itu dan datetime kira-kira sama di kedua arah. Tampaknya asumsi ini tidak sempurna tetapi mendekati karena nilainya mendekati 20000 md dengan hanya satu pengecualian.

Satu hal lagi yang menarik adalah bahwa biaya dasar hampir sama dengan Convert(date) single tunggal metode (yang harus hampir 0, karena server secara internal dapat mengekstrak bagian hari bilangan bulat langsung dari empat byte pertama datetime tipe data).

Kesimpulan

Jadi yang terlihat adalah varchar satu arah metode konversi membutuhkan waktu sekitar 1,8 dtk dan DateDiff . satu arah metode ini membutuhkan waktu sekitar 0,18 s. Saya mendasarkan ini pada waktu "CPU dasar" paling konservatif dalam pengujian saya dengan total 18458 md untuk 25.920.000 baris, jadi 23218 md / 25920000 =0,18 dtk. Peningkatan 10x yang nyata tampak seperti banyak, tetapi sejujurnya cukup kecil sampai Anda berurusan dengan ratusan ribu baris (penghematan 617k baris =1 detik).

Bahkan dengan sedikit peningkatan mutlak ini, menurut saya, DateAdd metode menang karena merupakan kombinasi terbaik dari kinerja dan kejelasan. Jawaban yang membutuhkan "angka ajaib" 0.50000004 akan menggigit seseorang suatu hari nanti (lima nol atau enam???), ditambah lagi lebih sulit untuk dipahami.

Catatan Tambahan

Ketika saya punya waktu, saya akan mengubah 0.50000004 ke '12:00:00.003' dan lihat bagaimana caranya. Itu dikonversi ke datetime yang sama nilai dan saya merasa lebih mudah untuk diingat.

Bagi mereka yang tertarik, pengujian di atas dijalankan di server di mana @@Version mengembalikan yang berikut:

Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) 9 Jul 2008 14:43:34 Hak Cipta (c) 1988-2008 Microsoft Corporation Standard Edition pada Windows NT 5.2 (Build 3790:Service Pack 2)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Apakah kueri ANSI JOIN vs. non-ANSI JOIN akan bekerja secara berbeda?

  2. Bagaimana cara menghindari kesalahan pembagian dengan nol dalam SQL?

  3. Hubungkan PHP ke MSSQL melalui PDO ODBC

  4. Gabungkan beberapa baris menjadi satu baris

  5. Log Transaksi SQL Server, Bagian 1:Dasar-dasar Pencatatan