Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

FORMAT() bagus dan semuanya, tapi…

Kembali ketika SQL Server 2012 masih dalam versi beta, saya membuat blog tentang FORMAT() new yang baru fungsi:SQL Server v.Next (Denali) :CTP3 T-SQL Enhancements :FORMAT().

Pada saat itu, saya sangat senang dengan fungsionalitas baru, sehingga saya bahkan tidak berpikir untuk melakukan pengujian kinerja apa pun. Saya memang membahas ini dalam posting blog yang lebih baru, tetapi semata-mata dalam konteks menghapus waktu dari datetime:Memotong waktu dari datetime – tindak lanjut.

Minggu lalu, teman baik saya Jason Horner (blog | @jasonhorner) menjebak saya dengan tweet ini:

Masalah saya dengan ini hanyalah FORMAT() terlihat nyaman, tetapi sangat tidak efisien dibandingkan dengan pendekatan lain (oh dan itu AS VARCHAR hal yang buruk juga). Jika Anda melakukan onesy-twosy ini dan untuk hasil yang kecil, saya tidak akan terlalu mengkhawatirkannya; tetapi pada skala, itu bisa menjadi sangat mahal. Mari saya ilustrasikan dengan sebuah contoh. Pertama, mari kita buat tabel kecil dengan 1000 tanggal pseudo-acak:

SELECT TOP (1000) d = DATEADD(DAY, CHECKSUM(NEWID())%1000, o.create_date)
  INTO dbo.dtTest
  FROM sys.all_objects AS o
  ORDER BY NEWID();
GO
CREATE CLUSTERED INDEX d ON dbo.dtTest(d);

Sekarang, mari kita perbaiki cache dengan data dari tabel ini, dan ilustrasikan tiga cara umum yang cenderung dilakukan orang tepat waktu:

SELECT d, 
  CONVERT(DATE, d), 
  CONVERT(CHAR(10), d, 120),
  FORMAT(d, 'yyyy-MM-dd')
FROM dbo.dtTest;

Sekarang, mari kita lakukan kueri individual yang menggunakan teknik berbeda ini. Kami akan menjalankannya setiap 5 kali dan kami akan menjalankan variasi berikut:

  1. Memilih semua 1.000 baris
  2. Memilih TOP (1) yang diurutkan berdasarkan kunci indeks berkerumun
  3. Menetapkan ke variabel (yang memaksa pemindaian penuh, tetapi mencegah rendering SSMS mengganggu kinerja)

Berikut scriptnya:

-- select all 1,000 rows
GO
SELECT d FROM dbo.dtTest;
GO 5
SELECT d = CONVERT(DATE, d) FROM dbo.dtTest;
GO 5
SELECT d = CONVERT(CHAR(10), d, 120) FROM dbo.dtTest;
GO 5
SELECT d = FORMAT(d, 'yyyy-MM-dd') FROM dbo.dtTest;
GO 5
 
-- select top 1
GO
SELECT TOP (1) d FROM dbo.dtTest ORDER BY d;
GO 5
SELECT TOP (1) CONVERT(DATE, d) FROM dbo.dtTest ORDER BY d;
GO 5
SELECT TOP (1) CONVERT(CHAR(10), d, 120) FROM dbo.dtTest ORDER BY d;
GO 5
SELECT TOP (1) FORMAT(d, 'yyyy-MM-dd') FROM dbo.dtTest ORDER BY d;
GO 5
 
-- force scan but leave SSMS mostly out of it
GO
DECLARE @d DATE;
SELECT @d = d FROM dbo.dtTest;
GO 5
DECLARE @d DATE;
SELECT @d = CONVERT(DATE, d) FROM dbo.dtTest;
GO 5
DECLARE @d CHAR(10);
SELECT @d = CONVERT(CHAR(10), d, 120) FROM dbo.dtTest;
GO 5
DECLARE @d CHAR(10);
SELECT @d = FORMAT(d, 'yyyy-MM-dd') FROM dbo.dtTest;
GO 5

Sekarang, kami dapat mengukur kinerja dengan kueri berikut (sistem saya cukup tenang; pada sistem Anda, Anda mungkin perlu melakukan pemfilteran lebih lanjut daripada hanya execution_count ):

SELECT 
  [t] = CONVERT(CHAR(255), t.[text]), 
  s.total_elapsed_time, 
  avg_elapsed_time = CONVERT(DECIMAL(12,2),s.total_elapsed_time / 5.0),
  s.total_worker_time, 
  avg_worker_time = CONVERT(DECIMAL(12,2),s.total_worker_time / 5.0),
  s.total_clr_time
FROM sys.dm_exec_query_stats AS s 
CROSS APPLY sys.dm_exec_sql_text(s.[sql_handle]) AS t
WHERE s.execution_count = 5
  AND t.[text] LIKE N'%dbo.dtTest%'
ORDER BY s.last_execution_time;

Hasil dalam kasus saya cukup konsisten:

Kueri (terpotong) Durasi (mikrodetik)
total_berlalu avg_elapsed total_clr
PILIH 1.000 baris SELECT d FROM dbo.dtTest ORDER BY d; 1,170 234.00 0
SELECT d = CONVERT(DATE, d) FROM dbo.dtTest ORDER BY d; 2,437 487.40 0
SELECT d = CONVERT(CHAR(10), d, 120) FROM dbo.dtTest ORD ... 151,521 30,304.20 0
SELECT d = FORMAT(d, 'yyyy-MM-dd') FROM dbo.dtTest ORDER ... 240,152 48,030.40 107,258
SELECT TOP (1) SELECT TOP (1) d FROM dbo.dtTest ORDER BY d; 251 50.20 0
SELECT TOP (1) CONVERT(DATE, d) FROM dbo.dtTest ORDER BY ... 440 88.00 0
SELECT TOP (1) CONVERT(CHAR(10), d, 120) FROM dbo.dtTest ... 301 60.20 0
SELECT TOP (1) FORMAT(d, 'yyyy-MM-dd') FROM dbo.dtTest O ... 1,094 218.80 589
Assign variable DECLARE @d DATE; SELECT @d = d FROM dbo.dtTest; 639 127.80 0
DECLARE @d DATE; SELECT @d = CONVERT(DATE, d) FROM dbo.d ... 644 128.80 0
DECLARE @d CHAR(10); SELECT @d = CONVERT(CHAR(10), d, 12 ... 1,972 394.40 0
DECLARE @d CHAR(10); SELECT @d = FORMAT(d, 'yyyy-MM-dd') ... 118,062 23,612.40 98,556

 

And to visualize the avg_elapsed_time keluaran (klik untuk memperbesar):

FORMAT() jelas kalah :hasil avg_elapsed_time (mikrodetik)

Apa yang dapat kita pelajari dari hasil ini (sekali lagi):

  1. Pertama dan terpenting, FORMAT() mahal .
  2. FORMAT() dapat, memang, memberikan lebih banyak fleksibilitas dan memberikan metode yang lebih intuitif yang konsisten dengan yang ada dalam bahasa lain seperti C#. Namun, selain overhead, dan sementara CONVERT() nomor gaya samar dan kurang lengkap, Anda mungkin harus menggunakan pendekatan yang lebih lama, karena FORMAT() hanya berlaku di SQL Server 2012 dan yang lebih baru.
  3. Bahkan standby CONVERT() metode bisa sangat mahal (meskipun hanya sangat parah dalam kasus di mana SSMS harus membuat hasil - itu jelas menangani string berbeda dari nilai tanggal).
  4. Hanya menarik nilai datetime langsung dari database selalu yang paling efisien. Anda harus membuat profil waktu tambahan yang diperlukan aplikasi Anda untuk memformat tanggal seperti yang diinginkan pada tingkat presentasi - kemungkinan besar Anda tidak ingin SQL Server terlibat dengan format cantik sama sekali (dan pada kenyataannya banyak yang akan berdebat bahwa di sinilah logika itu selalu berada).

Kami hanya berbicara mikrodetik di sini, tetapi kami juga hanya berbicara 1.000 baris. Skalakan itu ke ukuran tabel Anda yang sebenarnya, dan dampak dari memilih pendekatan pemformatan yang salah bisa sangat merusak.

Jika Anda ingin mencoba eksperimen ini di komputer Anda sendiri, saya telah mengunggah contoh skrip:FormatIsNiceAndAllBut.sql_.zip


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Menghubungkan F# ke Salesforce.com

  2. Bersenang-senang dengan Fitur Postgres Baru Django

  3. Apa yang Dilakukan dan Tidak Dilakukan Filestat Virtual, Memberitahu Anda Tentang Latensi I/O

  4. Operator Aritmatika SQL

  5. 18 database NoSQL open source gratis dan banyak digunakan