Metode mana yang memberikan kinerja terbaik saat menghapus bagian waktu dari bidang datetime di SQL Server?
a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)
atau
b) select cast(convert(char(11), getdate(), 113) as datetime)
Metode kedua memang mengirim beberapa byte lagi, tetapi itu mungkin tidak sepenting kecepatan konversi.
Keduanya juga tampak sangat cepat, tetapi mungkin ada perbedaan dalam kecepatan ketika berhadapan dengan ratusan ribu atau lebih baris?
Juga, mungkinkah ada metode yang lebih baik untuk menghilangkan bagian waktu datetime dalam SQL?
Jawaban:
Secara ketat, metode
a
adalah sumber daya yang paling sedikit:Terbukti kurang intensif CPU untuk durasi total yang sama satu juta baris oleh seseorang dengan terlalu banyak waktu di tangan mereka: Cara paling efisien dalam SQL Server untuk mendapatkan tanggal dari tanggal + waktu?
Saya melihat tes serupa di tempat lain dengan hasil yang sama juga.
Saya lebih suka DATEADD / DATEIFF karena:
Contoh: Mengapa ekspresi KASUS saya tidak deterministik?
Edit, Okt 2011
Untuk SQL Server 2008+, Anda dapat CAST untuk
date
yaituCAST(getdate() AS date)
. Atau cukup gunakandate
tipe data sehingga tidak ada waktu untuk menghapus.Edit, Jan 2012
Sebuah contoh yang dikerjakan tentang seberapa fleksibelnya ini: Perlu untuk menghitung dengan waktu bulat atau angka tanggal di sql server
Edit, Mei 2012
Jangan gunakan ini di klausa WHERE dan sejenisnya tanpa berpikir: menambahkan fungsi atau CAST ke kolom membatalkan penggunaan indeks. Lihat nomor 2 di sini: http://www.simple-talk.com/sql/t-sql-programming/ten-common-sql-programming-mistakes/
Sekarang, ini memang memiliki contoh versi pengoptimal SQL Server yang mengelola CAST hingga saat ini dengan benar, tetapi umumnya itu akan menjadi ide yang buruk ...
Edit, Sep 2018, untuk datetime2
sumber
DATE
waktu data menjengkelkan terbatas pada apa yang akan membiarkan Anda melakukan berkaitan dengan hal-hal seperti dateadd, datediff dan berinteraksi dengan tipe data tanggal / waktu lainnya. Untuk kasus-kasus itu,DATEADD()
pendekatan itu memerintah raja.0218
bukan2018
sebagai tahun danDATEDIFF
bagian dari pernyataan Anda melempar pengecualianThe conversion of a datetime2 data type to a datetime data type resulted in an out-of-range datetime value
Coba:select DATEDIFF(dd, 0, convert(datetime2(0), '0218-09-12', 120))
SELECT DATEDIFF(dd, '19000101', convert(datetime2(0), '0218-09-12', 120))
Di SQL Server 2008, Anda dapat menggunakan:
sumber
datetime
kedate
, dan solusi Anda secara efektif bermuara pada justCONVERT(DATE,getdate())
, yang telah disarankan lebih dari sekali.CAST(GETDATE() AS DATE)
atau ANSI ketatCAST(CURRENT_TIMESTAMP AS DATE)
yang saya pikir tidak berharga. Tetap dengan yang pertama.Tentu saja ini adalah utas lama tetapi untuk membuatnya lengkap.
Dari SQL 2008 Anda dapat menggunakan DATE datatype sehingga Anda dapat melakukannya:
sumber
... bukan solusi yang baik, sesuai komentar di bawah.
Saya akan menghapus jawaban ini, tetapi saya akan meninggalkannya di sini sebagai contoh tandingan karena saya pikir penjelasan komentator tentang mengapa itu bukan ide yang baik masih berguna.
sumber
Dalam SQL Server 2008, ada tipe data DATE (juga tipe data TIME).
atau
sumber
Ini jawaban lain, dari pertanyaan rangkap lain :
Metode angka ajaib ini melakukan sedikit lebih cepat daripada metode DATEADD. (Sepertinya ~ 10%)
Waktu CPU pada beberapa putaran satu juta catatan:
Tetapi perhatikan bahwa angka-angka ini mungkin tidak relevan karena mereka sudah SANGAT cepat. Kecuali jika saya memiliki rekor 100.000 atau lebih, saya bahkan tidak bisa mendapatkan Waktu CPU untuk membaca di atas nol.
Mengingat fakta bahwa DateAdd dimaksudkan untuk tujuan ini dan lebih kuat, saya akan mengatakan menggunakan DateAdd.
sumber
'12:00:00.003'
yang menurut saya jauh lebih baik.sumber
Saya sangat suka:
The
120
Kode Format akan memaksa tanggal ke dalam ISO 8601 standar:Sangat mudah digunakan di dplyr (
R
) dan panda (Python
)!sumber
WASPADALAH!
Metode a) dan b) TIDAK selalu memiliki output yang sama!
Keluaran:
2014-01-01 00:00:00.000
Keluaran:
2013-12-31 00:00:00.000
(Diuji pada MS SQL Server 2005 dan 2008 R2)
EDIT: Menurut komentar Adam, ini tidak dapat terjadi jika Anda membaca nilai tanggal dari tabel, tetapi itu bisa terjadi jika Anda memberikan nilai tanggal Anda sebagai literal (contoh: sebagai parameter dari prosedur tersimpan yang dipanggil melalui ADO.NET).
sumber
DATETIME
kolom. Yang tertinggi tersedia .997 Dari: msdn.microsoft.com/en-us/library/ms187819.aspx Anda akan melihat bahwa nilai dibulatkan untuk memiliki tempat keseribu ke 0, 3, atau 7. OP tidak akan melihat nilai dari tes Anda di tabel mereka.Strip waktu pada sisipan / pembaruan di tempat pertama. Sedangkan untuk konversi on-the-fly, tidak ada yang dapat mengalahkan fungsi pemeliharaan yang ditentukan pengguna:
Implementasi
date_only
bisa apa saja yang Anda suka - sekarang sudah disarikan dan kode panggilan jauh lebih bersih.sumber
WHERE DateAdd(DateDiff(Column)) = @DateValue
tidak akan menggunakan indeks. Di sisi lain,WHERE Column >= dbo.UDF(@DateValue) AND Column < dbo.UDF(@DateValue + 1)
adalah SARGable. Jadi berhati-hatilah bagaimana Anda mengatakannya.Lihat pertanyaan ini:
Bagaimana saya bisa memotong datetime di SQL Server?
Apa pun yang Anda lakukan, jangan gunakan metode string . Itu tentang cara terburuk Anda bisa melakukannya.
sumber
Sudah dijawab tetapi tidak akan membuang ini di luar sana juga ... ini seharusnya juga membentuk sebelumnya dengan baik tetapi berfungsi dengan membuang desimal (yang menyimpan waktu) dari float dan mengembalikan hanya seluruh bagian (yang merupakan tanggal)
kedua kalinya saya menemukan solusi ini ... saya mengambil kode ini
sumber
Metode ini tidak menggunakan fungsi string.
Date
pada dasarnya adalah tipe data nyata dengan digit sebelum desimal adalah pecahan sehari.ini saya kira akan lebih cepat daripada banyak.
sumber
Bagi saya kode di bawah ini selalu menjadi pemenang:
sumber
pilih CONVERT (char (10), GetDate (), 126)
sumber
Saya pikir maksud Anda
cast(floor(cast(getdate()as float))as datetime)
real hanya 32-bit, dan bisa kehilangan beberapa informasi
Ini tercepat
cast(cast(getdate()+x-0.5 as int)as datetime)
... meskipun hanya sekitar 10% lebih cepat
(about 0.49 microseconds CPU vs. 0.58)
Ini direkomendasikan, dan membutuhkan waktu yang sama dalam pengujian saya sekarang:
DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)
Dalam SQL 2008, fungsi SQL CLR adalah sekitar 5 kali lebih cepat daripada menggunakan fungsi SQL, pada 1,35 mikrodetik versus 6,5 mikroskopi, menunjukkan biaya panggilan fungsi yang jauh lebih rendah untuk fungsi SQL CLR dibandingkan dengan UDF SQL sederhana.
Dalam SQL 2005, fungsi SQL CLR adalah 16 kali lebih cepat, per pengujian saya, dibandingkan dengan fungsi lambat ini:
sumber
Bagaimana dengan
select cast(cast my_datetime_field as date) as datetime)
? Ini menghasilkan tanggal yang sama, dengan waktu yang ditentukan untuk 00:00, tetapi menghindari konversi ke teks dan juga menghindari pembulatan numerik eksplisit.sumber
Saya pikir jika Anda berpegang teguh pada
TSQL
hal ini, ini adalah cara tercepat untuk memotong waktu:Saya menemukan metode pemotongan ini sekitar 5% lebih cepat daripada
DateAdd
metode ini. Dan ini dapat dengan mudah dimodifikasi untuk dibulatkan ke hari terdekat seperti ini:sumber
Di sini saya membuat fungsi untuk menghapus beberapa bagian datetime untuk SQL Server. Pemakaian:
create function dbo.uf_RoundDateTime(@dt as datetime, @part as char) returns datetime as begin if CHARINDEX( @part, 'smhd',0) = 0 return @dt; return cast( Case @part when 's' then convert(varchar(19), @dt, 126) when 'm' then convert(varchar(17), @dt, 126) + '00' when 'h' then convert(varchar(14), @dt, 126) + '00:00' when 'd' then convert(varchar(14), @dt, 112) end as datetime ) end
sumber
Kalau-kalau ada orang mencari versi Sybase di sini karena beberapa versi di atas tidak berfungsi
sumber
cast
: Untuk SQL Server 2008+, Anda dapat melakukan CAST hingga saat ini. Atau gunakan saja tanggal sehingga tidak ada waktu untuk menghapus.datetime
kedate
: tak satu pun dari mereka memiliki format yang melekat.Jika memungkinkan, untuk hal-hal khusus seperti ini, saya suka menggunakan fungsi CLR.
Pada kasus ini:
sumber
Saya, secara pribadi, hampir selalu menggunakan fungsi yang Ditentukan Pengguna untuk ini jika berurusan dengan SQL Server 2005 (atau versi yang lebih rendah), namun, perlu dicatat bahwa ada kelemahan spesifik untuk menggunakan UDF, terutama jika menerapkannya pada klausa WHERE (lihat di bawah dan komentar pada jawaban ini untuk perincian lebih lanjut). Jika menggunakan SQL Server 2008 (atau lebih tinggi) - lihat di bawah.
Bahkan, untuk sebagian besar database yang saya buat, saya menambahkan UDF ini tepat di dekat awal karena saya tahu ada 99% peluang saya akan membutuhkannya cepat atau lambat.
Saya membuat satu untuk "date only" & "time only" (walaupun "date only" satu adalah yang paling banyak digunakan dari keduanya).
Berikut ini beberapa tautan ke berbagai UDF terkait tanggal:
Essential SQL Server Tanggal, Waktu dan Fungsi DateTime
Dapatkan Fungsi Hanya Tanggal
Tautan terakhir itu menunjukkan tidak kurang dari 3 cara berbeda untuk mendapatkan tanggal hanya bagian dari bidang waktu dan menyebutkan beberapa pro dan kontra dari setiap pendekatan.
Jika menggunakan UDF, harus dicatat bahwa Anda harus mencoba menghindari menggunakan UDF sebagai bagian dari klausa WHERE dalam kueri karena ini akan sangat menghambat kinerja kueri. Alasan utama untuk ini adalah bahwa menggunakan UDF dalam klausa WHERE menjadikan klausa sebagai non-sargable , yang berarti bahwa SQL Server tidak lagi dapat menggunakan indeks dengan klausa itu untuk meningkatkan kecepatan eksekusi permintaan. Dengan merujuk pada penggunaan UDF saya sendiri, saya akan sering menggunakan kolom tanggal "mentah" dalam klausa WHERE, tetapi menerapkan UDF ke kolom SELECT. Dengan cara ini, UDF hanya diterapkan pada set-hasil yang difilter dan tidak setiap baris tabel sebagai bagian dari filter.
Tentu saja, pendekatan terbaik mutlak untuk ini adalah dengan menggunakan SQL Server 2008 (atau lebih tinggi) dan memisahkan tanggal dan waktu Anda , karena mesin basis data SQL Server kemudian secara asli menyediakan komponen tanggal dan waktu, dan secara efisien dapat meminta ini secara mandiri tanpa perlu UDF atau mekanisme lain untuk mengekstrak bagian tanggal atau waktu dari tipe datetime komposit.
sumber
WHERE DateColumn >= {TimeTruncatingExpression}(@DateValue) AND DateColumn < {TimeTruncatingExpression}(@DateValue + 1)
. Saya merasa harus mengatakan sesuatu karena Anda mengatakan "Saya hampir selalu menggunakan UDFs" tidak menjelaskan kekurangannya, atau cara membuat kueri hanya-tanggal SARGable.Saya akan menggunakan:
Dengan demikian secara efektif membuat bidang baru dari bidang tanggal yang sudah Anda miliki.
sumber
datetime
nilai, mengubahnya menjadi string, menggabungkannya menjadi satu dan akhirnya mengonversi hasilnya kembali menjadidatetime
lebih baik daripada misalnya melakukan perhitungan langsung pada yang aslidatetime
( metodeDATEADD
/DATEDIFF
)?MM
danDD
? Tidak ada fungsi seperti itu di SQL Server.