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

Jawaban Teratas untuk 5 Pertanyaan Pembakaran pada Fungsi COALESCE di SQL Server

Seberapa keren fungsi COALESCE dalam SQL?

Cukup keren untuk menjadi sangat penting bagi saya. Dan saya akan dengan senang hati mempekerjakan orang baru yang tidak memiliki kebiasaan buruk untuk mengabaikan tujuan COALESCE. Itu termasuk ekspresi dan fungsi lain untuk menangani situasi serupa.

Hari ini, Anda akan menemukan jawaban atas lima pertanyaan yang paling sering diajukan tentang ekspresi SQL COALESCE. Salah satunya sedang diperdebatkan berulang kali.

Bisakah kita mulai?

Apa Kegunaan Fungsi COALESCE dalam SQL?

Itu bisa dijawab dengan 2 kata:menangani nulls .

Null adalah kekosongan nilai. Dengan kata lain, tidak diketahui. Ini berbeda dari string kosong atau angka nol. Menangani null membutuhkan penggunaan ekspresi dan fungsi. Salah satunya adalah COALESCE.

Untuk memahami apa yang saya maksud, lihat pernyataan di bawah ini:

DECLARE @number INT

SELECT @number + 33587

Apakah akan berjalan dengan baik? Ini akan.

Apakah ada masalah? Tidak ada, saat ini.

Tetapi pernyataan akan menghasilkan NULL karena menambahkan null ke angka sama dengan NULL.

Jika semua pertanyaan Anda hanya jatuh ke level ini, Anda dapat berhenti membaca. Tapi tentu saja tidak. Kami dibayar lebih dari sekadar memproduksi kode semacam ini.

Sekarang, mari kita tambahkan sedikit 'bencana':

DECLARE @number INT

SET @number = @number + 33587

UPDATE myTable
set col1 = @number   -- Surprise! col1 is NOT NULLABLE
where ID = 1

PRINT 'Success!'

Eksekusi kode di atas akan menemui jalan buntu ketika mencapai pernyataan UPDATE. Itu tidak akan mencetak 'Berhasil!' karena Anda tidak dapat meletakkan nol pada kolom yang tidak dapat dibatalkan. Apakah pernyataan ini menjelaskan mengapa kita perlu menangani nulls?

Mari kita ubah kode untuk menambahkan jaring pengaman:

DECLARE @number INT

SET @number = COALESCE(@number,0) + 33587     -- our safety net. Thanks to COALESCE.

UPDATE myTable
set col1 = @number               -- Disaster averted!
where ID = 1

PRINT 'Success!'

COALESCE akan mengubah nilai nol menjadi nol, dan jumlah tidak akan menjadi nol.

Pelajarannya adalah, COALESCE adalah salah satu jaring pengaman terhadap nol. Lebih baik lagi, menangani null dengan benar dalam kode SQL Anda mengurangi sakit kepala dan memungkinkan Anda pulang lebih awal. Itu pasti.

Sekarang Anda mengerti mengapa saya ingin di tim saya seseorang yang rajin menangani nulls.

Contoh Lebih Praktis dalam Penggunaan SQL COALESCE

Mari kita lihat contoh yang lebih praktis.

Misalkan Anda tinggal di wilayah di mana beberapa orang memiliki nama tengah, tetapi yang lain tidak. Bagaimana Anda akan membentuk nama lengkap dari nama depan, nama tengah, dan nama belakang tanpa jatuh ke dalam perangkap nol?

Inilah salah satu solusi yang memungkinkan menggunakan COALESCE:

USE AdventureWorks
GO

SELECT
p.LastName + ', ' + p.FirstName + ' ' + COALESCE(p.MiddleName + ' ','') AS FullName
FROM Person.Person p

Contoh lain:misalkan Anda seorang karyawan di perusahaan di mana gaji kotor dihitung secara berbeda untuk setiap karyawan. Untuk beberapa dari mereka, ada tarif per jam. Yang lain dibayar dengan tarif mingguan atau bulanan.

Berikut adalah contoh tabel bersama dengan solusi kueri menggunakan COALESCE:

-- STEP 1: Create the table
CREATE TABLE EmployeeWages (
    employee_id INT PRIMARY KEY,
    hourly_rate SMALLMONEY,
    weekly_rate SMALLMONEY,
    monthly_rate MONEY,
    CHECK(
        hourly_rate IS NOT NULL OR
        weekly_rate IS NOT NULL OR
        monthly_rate IS NOT NULL)
);

-- STEP 2: Insert data
INSERT INTO
    EmployeeWages(
        employee_id,
        hourly_rate,
        weekly_rate,
        monthly_rate
    )
VALUES
    (1,60, NULL,NULL),
    (2,40, NULL,NULL),
    (3,NULL, 1000,NULL),
    (4,NULL, NULL,7000),
    (5,NULL, NULL,5000);

-- STEP 3: Query the monthly salary.
SELECT
    employee_id,
    COALESCE(
        hourly_rate*22.00*8.00,
        weekly_rate*4.00,
        monthly_rate
    ) AS monthly_salary
FROM
    EmployeeWages;

Tabel berisi mode pembayaran yang berbeda per ID karyawan. Kueri mengharuskan Anda untuk menampilkan gaji bulanan untuk semua.

Di sinilah COALESCE akan bersinar:ia menerima daftar nilai, dan bisa ada sejumlah item. COALESCE akan memilih yang pertama yang bukan null:

Rapi, bukan?

Bagaimana COALESCE Bekerja di SQL?

Definisi COALESCE adalah ekspresi yang menampilkan nilai bukan nol pertama dari daftar nilai. Sintaks COALESCE adalah:

COALESCE ( ekspresi [ ,…n ] )

Contoh kami sebelumnya dengan mode pembayaran yang berbeda untuk upah menggambarkan hal ini.

Apa yang Tersembunyi

Di bawah tenda, fungsi COALESCE dalam SQL adalah ekspresi berlapis gula untuk ekspresi CASE yang lebih lama. Ini menghilangkan kebutuhan mengetik CASE yang setara, yang lebih panjang (dan melelahkan, untuk juru ketik yang malas seperti saya). Hasilnya akan sama.

Bisakah kita membuktikannya? Ya! Pertama, Microsoft mengakuinya.

Tapi bagus untuk kami, Microsoft memasukkannya ke dalam Rencana Eksekusi. Jadi, kita tahu apa yang sedang terjadi.

Mari kita coba menggunakan contoh sebelumnya dengan upah. Namun sebelum Anda menjalankan kembali kueri di bawah, aktifkan Sertakan Rencana Eksekusi Aktual atau cukup tekan CTRL-M .

SELECT
    employee_id,
    COALESCE(
        hourly_rate * 22.00 * 8.00,
        weekly_rate * 4.00,
        monthly_rate
    ) AS monthly_salary
FROM
    EmployeeWages;

Klik Rencana Eksekusi tab dalam hasil. Kelihatannya sederhana, tetapi permata tersembunyi kami terletak di Compute Scalar simpul. Saat Anda mengarahkan mouse ke atasnya, Anda melihat ekspresi bernama Expr1002 (Gambar 2). Apa itu?

Mari kita menggali lebih dalam. Klik kanan dan pilih Show Execution Plan XML . Jendela baru akan muncul. Perhatikan Gambar 3 di bawah ini:

Ada pernyataan KASUS Anda. Di bawah ini adalah semuanya diformat dan diindentasi agar mudah dibaca:

CASE WHEN CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[hourly_rate],0)
                                            *(22.00)*(8.00) IS NOT NULL
     THEN CONVERT_IMPLICIT(numeric(23,8),CONVERT_IMPLICIT(numeric(10,4),
                       [TestDatabase].[dbo].[EmployeeWages].[hourly_rate],0)*(22.00)*(8.00),0)
     ELSE CASE WHEN    
          CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)
                                            *(4.00) IS NOT NULL
          THEN CONVERT_IMPLICIT(numeric(23,8),CONVERT_IMPLICIT(numeric(10,4),                                                         
                       [TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)*(4.00),0)
          ELSE CONVERT_IMPLICIT(numeric(23,8),[TestDatabase].[dbo].[EmployeeWages].[monthly_rate],0)
          END
END

Itu cukup lama dibandingkan dengan

COALESCE(
        hourly_rate * 22.00 * 8.00,
        weekly_rate * 4.00,
        monthly_rate
        )

Itulah yang dilakukan SQL Server dengan kueri kami dengan COALESCE. Semuanya untuk mendapatkan nilai pertama yang bukan nol dalam daftar nilai.

Bisakah Lebih Pendek?

Saya tahu apa yang Anda pikirkan. Jika SQL Server melakukan itu selama pemrosesan kueri, COALESCE harus lambat. Belum lagi beberapa penampilan CONVERT_IMPLICIT. Apakah Anda lebih suka menggunakan alternatif?

Pertama, Anda dapat mengetik sendiri pernyataan CASE yang lebih pendek. Atau, Anda dapat menggunakan ISNULL. Lebih lanjut tentang itu nanti. Berbicara tentang lambat, saya sudah membahasnya sebelum posting ini berakhir.

Apa Perbedaan Antara COALESCE dan ISNULL dalam SQL?

Salah satu alternatif untuk COALESCE adalah ISNULL. Menggunakan COALESCE dengan 2 nilai membuatnya mirip dengan ISNULL. Setidaknya, hasilnya terlihat serupa. Namun, ada perbedaan yang mencolok. Anda dapat menggunakannya sebagai panduan untuk memutuskan apakah Anda akan menggunakan COALESCE atau ISNULL.

(1) ISNULL Menerima 2 Argumen. COALESCE Menerima Daftar Argumen

Ini adalah perbedaan yang paling jelas. Dari sintaksnya pasti berbeda.

ISNULL ( check_expression , replacement_value )
COALESCE ( ekspresi [ ,…n ] )

Saat Anda menggunakan keduanya dengan 2 argumen, hasilnya sama. 2 pernyataan di bawah ini akan menghasilkan 1:

SELECT ISNULL(NULL, 1)
SELECT COALESCE(NULL, 1)

Meskipun hasilnya sama, namun artinya berbeda:

  • ISNULL(NULL, 1) mengembalikan 1 karena argumen pertama adalah NULL.
  • COALESCE(NULL, 1) mengembalikan 1 karena 1 adalah nilai bukan nol pertama dalam daftar .

(2) COALESCE adalah Standar SQL-92

Betul sekali. Anda dapat memeriksanya. Misalnya, jika Anda ingin mem-porting kode SQL Anda ke MySQL dari SQL Server, COALESCE akan berfungsi sama. Lihat Gambar 4 dan bandingkan hasil dari Gambar 1:

Menggunakan ISNULL di MySQL, bagaimanapun, akan memicu kesalahan jika Anda menggunakan sintaks SQL Server.

misalnya, Jalankan yang berikut ini di SQL Server Management Studio dan MySQL Workbench:

SELECT ISNULL(null,1)

Apa yang terjadi? Di SQL Server, outputnya adalah 1. Tetapi di MySQL, outputnya adalah kesalahan:

06:36:52 SELECT ISNULL(null,1) Kode Kesalahan:1582. Jumlah parameter salah dalam panggilan ke fungsi asli 'ISNULL'

Masalahnya, ISNULL di MySQL menerima 1 argumen dan mengembalikan 1 jika argumennya nol. Jika tidak, ia mengembalikan 0.

(3) Melewati 2 Null di COALESCE Memicu Kesalahan. Tidak masalah dengan ISNULL

Ini akan memicu kesalahan:

SELECT COALESCE(NULL, NULL)

Kesalahannya adalah:'Setidaknya salah satu argumen untuk COALESCE harus berupa ekspresi yang bukan konstanta NULL.'

Ini akan baik-baik saja:

SELECT ISNULL(NULL, NULL)

Mengubah kode COALESCE menjadi sesuatu yang serupa di bawah ini tidak akan memicu kesalahan:

DECLARE @value INT = NULL
SELECT COALESCE(@value,null)

Itu terjadi karena @nilai bukan konstanta nol.

(4) SQL COALESCE Dikonversi ke CASE. ISNULL Tetap ISNULL

Kami telah melihat ini di ‘Bagaimana COALESCE Bekerja di SQL?’ bagian. Di sini, mari kita periksa contoh lain:

SELECT
P.LastName + ', ' + P.FirstName + ' ' + COALESCE(P.MiddleName + ' ','') AS FullName
FROM Person.Person p

Pemeriksaan XML Rencana Eksekusi untuk operator skalar mengungkapkan konversi ke KASUS:

 [AdventureWorks].[Person].[Person].[LastName] as [p].[LastName]+N', '
+[AdventureWorks].[Person].[Person].[FirstName] as [p].[FirstName]+N' '
+CASE WHEN ([AdventureWorks].[Person].[Person].[MiddleName] as [p].[MiddleName]+N' ') IS NOT NULL
      THEN [AdventureWorks].[Person].[Person].[MiddleName] as [p].[MiddleName]+N' '
      ELSE N''
 END

Sekarang, jalankan kueri yang setara menggunakan ISNULL:

SELECT
P.LastName + ', ' + P.FirstName + ' ' + ISNULL(P.MiddleName + ' ','') AS FullName
FROM Person.Person p

Kemudian, periksa Execution Plan XML untuk operator skalar:

 [AdventureWorks].[Person].[Person].[LastName] as [p].[LastName]+N', '
+[AdventureWorks].[Person].[Person].[FirstName] as [p].[FirstName]+N' '
+isnull([AdventureWorks].[Person].[Person].[MiddleName] as [p].[MiddleName]+N' ',N'')

ISNULL tetaplah ISNULL.

(5) Tipe Data Ekspresi yang Dihasilkan Berbeda

Penentuan tipe data dari ekspresi yang dihasilkan juga berbeda antara COALESCE dan ISNULL:

  • ISNULL menggunakan tipe data dari parameter pertama.
  • COALESCE mengembalikan tipe data dari nilai dengan prioritas tertinggi.

Untuk daftar prioritas tipe data, lihat tautan ini.

Mari kita ambil contoh:

SELECT
 employee_id
,COALESCE(CAST(weekly_rate * 4 AS MONEY),0.0000) AS monthly_rate
FROM EmployeeWages

Kemudian, periksa konversi ke CASE di Execution Plan XML :

CASE WHEN CONVERT(money,[TestDatabase].[dbo].[EmployeeWages].[weekly_rate]
                                           *CONVERT_IMPLICIT(smallmoney,[@1],0),0) IS NOT NULL
     THEN CONVERT_IMPLICIT(numeric(19,4), CONVERT(money,[TestDatabase].[dbo].[EmployeeWages].[weekly_rate]
                                           *CONVERT_IMPLICIT(smallmoney,[@1],0),0),0)
     ELSE (0.0000)
END

Dalam ekspresi CASE di atas, tipe data dari hasilnya adalah numerik(19,4).

Mengapa? Ini memiliki prioritas lebih tinggi daripada uang dan uang kecil bahkan jika Anda MEMBUATnya ke uang . Mengapa numerik dan bukan uang ? Karena konstanta 0,0000.

Jika Anda bertanya-tanya apa itu @1, XML Rencana Eksekusi memiliki jawabannya. Ini adalah angka konstan 4.

<ParameterList>
 <ColumnReference Column="@1" ParameterDataType="int" ParameterCompiledValue="(4)"  
       ParameterRuntimeValue="(4)" />
</ParameterList>

Mari kita coba dengan ISNULL:

SELECT
 employee_id
,ISNULL(CAST(weekly_rate * 4 AS MONEY),0.0000) AS monthly_rate
FROM EmployeeWages

Sekali lagi, cari Operator Skalar ScalarString :

ISNULL(CONVERT(MONEY,[TestDatabase].[dbo].[EmployeeWages].[weekly_rate]*($4.0000),0),($0.0000))

Terakhir, tipe data dari ekspresi yang dihasilkan adalah uang . Ini adalah tipe data dari argumen pertama.

Cara Mengakali Prioritas Data

Anda dapat 'mengakali' prioritas data dengan menambahkan beberapa perubahan pada kode Anda. Sebelumnya, hasilnya memiliki numerik tipe data. Jika Anda ingin hasilnya menjadi uang tipe data dan singkirkan CONVERT_IMPLICIT, lakukan hal berikut:

SELECT
 employee_id
,COALESCE(CAST(weekly_rate AS MONEY) * ($4.0000),($0.0000)) AS monthly_rate
FROM EmployeeWages

Apakah Anda memperhatikan konstanta ($4.000) dan ($0.0000)? Itu adalah uang konstanta. Apa yang terjadi selanjutnya muncul di Execution Plan XML ScalarString :

CASE WHEN CONVERT(money,[TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)*($4.0000) IS NOT NULL 
     THEN CONVERT(money,[TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)*($4.0000) 
     ELSE ($0.0000) 
END

Itu lebih baik. Ini lebih pendek, dan CONVERT_IMPLICIT hilang. Dan tipe data yang dihasilkan adalah uang .

(6) NULLability dari Ekspresi yang Dihasilkan Berbeda

ISNULL(NULL, 1) dan COALESCE(NULL, 1) memiliki hasil yang serupa, tetapi nilai nullability-nya berbeda. COALESCE tidak dapat dibatalkan. ISNULL tidak. Anda dapat melihat ini saat menggunakannya pada kolom yang dihitung.

Mari kita lihat sebuah contoh. Pernyataan di bawah ini akan memicu kesalahan karena PRIMARY KEY tidak dapat menerima nilai NULL. Pada saat yang sama, nullability dari ekspresi COALESCE untuk column2 mengevaluasi ke NULL.

CREATE TABLE NullabilityDemo  
(  
  column1 INTEGER NULL,  
  column2 AS COALESCE(column1, 0) PRIMARY KEY,  
  column3 AS ISNULL(column1, 0)  
);

Pernyataan ini berhasil karena nullability dari fungsi ISNULL dievaluasi sebagai NOT NULL.

CREATE TABLE NullabilityDemo  
(  
  column1 INTEGER NULL,  
  column2 AS COALESCE(column1, 0),  
  column3 AS ISNULL(column1, 0) PRIMARY KEY  
);

(7) Argumen Kiri ISNULL Dievaluasi Sekali. Ini Berlawanan dengan COALESCE

Perhatikan kembali contoh sebelumnya:

SELECT
    employee_id,
    COALESCE(
        hourly_rate*22.00*8.00,
        weekly_rate*4.00,
        monthly_rate
    ) AS monthly_salary
FROM
    EmployeeWages;

Kemudian, periksa ScalarString untuk ini:

CASE WHEN CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[hourly_rate],0)
                                              *(22.00)*(8.00) IS NOT NULL 
     THEN CONVERT_IMPLICIT(numeric(23,8),CONVERT_IMPLICIT(numeric(10,4),
                                              [TestDatabase].[dbo].[EmployeeWages].[hourly_rate],0)
                                              *(22.00)*(8.00),0) 
     ELSE CASE WHEN CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)
                                              *(4.00) IS NOT NULL 
               THEN CONVERT_IMPLICIT(numeric(23,8),CONVERT_IMPLICIT(numeric(10,4),
                                        [TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)*(4.00),0) 
               ELSE CONVERT_IMPLICIT(numeric(23,8),[TestDatabase].[dbo].[EmployeeWages].[monthly_rate],0) 
          END 
END

Ketika fungsi COALESCE dalam SQL dikonversi ke CASE, setiap ekspresi dievaluasi dua kali (kecuali yang terakhir). Seperti yang Anda lihat di atas, tarif_jam*22.00*8.00 muncul dua kali. Hal yang sama dengan tarif_mingguan*4.00 . Ekspresi terakhir, tarif_bulanan , muncul sekali.

Karena COALESCE akan mengevaluasi ekspresi dua kali, mungkin ada penalti kinerja. Lebih lanjut tentang ini nanti.

Namun, lihat padanan ISNULL:

SELECT
 employee_id,
 ISNULL(hourly_rate * 22.00 * 8.00,ISNULL(weekly_rate * 4.00,monthly_rate)) AS  
                                                       monthly_salary
FROM EmployeeWages

Kemudian, kami memeriksa ScalarString di XML Rencana Eksekusi :

isnull(CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[hourly_rate],0)*(22.00)*(8.00),
       CONVERT_IMPLICIT(numeric(19,8),
isnull(CONVERT_IMPLICIT(numeric(10,4),[TestDatabase].[dbo].[EmployeeWages].[weekly_rate],0)*(4.00),
CONVERT_IMPLICIT(numeric(14,6),[TestDatabase].[dbo].[EmployeeWages].[monthly_rate],0)),0))

Seperti yang Anda lihat di atas, tarif_jam , tarif_mingguan , dan tarif_bulanan muncul hanya sekali. Jadi, Anda tidak perlu khawatir ekspresi dievaluasi dua kali dengan ISNULL.

Dapatkah Kita Menggunakan COALESCE dalam Klausa WHERE?

Tentu saja. Tidak ada cara yang lebih baik selain menunjukkan contoh untuk membuktikannya.

-- Query all the names in Person table with no middle name

USE AdventureWorks
GO

SELECT
 p.LastName
,p.FirstName
FROM person.Person p
WHERE COALESCE(p.MiddleName,'') = ''

COALESCE akan mengembalikan string kosong jika MiddleName adalah NULL. Tentu saja, ada cara yang lebih singkat untuk menghasilkan hasilnya. Tapi ini menunjukkan COALESCE bekerja dalam klausa WHERE.

Mana yang Lebih Cepat:COALESCE atau ISNULL?

Akhirnya, kita sampai pada topik hangat:Performa!

Anda akan mendapatkan banyak halaman dengan tes dan perbandingan, tetapi akan ada pertempuran antara pendukung COALESCE dan ISNULL dalam komentar. Kami akan membersihkan debu dan asap dari perang tersebut.

Mana yang lebih cepat:COALESCE atau ISNULL? Mari saya mulai dengan mengatakan bahwa jawabannya adalah:

(drum bergulir)

TERGANTUNG!

(rahang ternganga)

Kecewa? Saya akan menjelaskannya sebentar lagi.

Pertama, saya setuju bahwa keduanya tampaknya memiliki perbedaan kinerja jika Anda menggunakan waktu yang telah berlalu sebagai metrik Anda. Beberapa orang mendukung fakta ini ketika SQL Server menerjemahkan COALESCE ke pernyataan CASE. Sementara itu, ISNULL tetap apa adanya.

Orang lain mungkin bernalar berbeda karena hasil yang berbeda-beda. Juga, bagi mereka, mengubah COALESCE ke CASE lebih cepat daripada kita mengedipkan mata. Sama seperti apa yang ditunjukkan di utas ini, perbedaan kinerja 'sangat kecil'. Saya setuju. Ini artikel lain yang mengatakan bahwa perbedaannya 'kecil'.

Namun, inilah masalahnya:dapatkah kita memercayai waktu yang berlalu sangat kecil sebagai metrik? Yang benar-benar penting adalah seberapa banyak pembacaan logis yang dimiliki kueri. Itulah yang akan kami tunjukkan dalam contoh kami berikutnya.

(Lihat artikel saya yang lain tentang pembacaan logis dan mengapa faktor ini yang membuat kueri Anda tertinggal.)

Contoh 1

Mari kita periksa contoh yang sama dan bandingkan pembacaan logis dan rencana eksekusi mereka. Sebelum menjalankan ini, pastikan STATISTICS IO AKTIF dan Sertakan Rencana Eksekusi Aktual diaktifkan.

SET STATISTICS IO ON

SELECT
P.LastName + ', ' + P.FirstName + ' ' + COALESCE(P.MiddleName + ' ','') AS FullName
FROM Person.Person p

SELECT
P.LastName + ', ' + P.FirstName + ' ' + ISNULL(P.MiddleName + ' ','') AS FullName
FROM Person.Person p

Ini faktanya:

Pembacaan logis untuk kedua kueri adalah sama. Keduanya 107 * 8KB halaman. Jika kita memiliki sejuta catatan, pembacaan logis akan meningkat, tentu saja. Tetapi pembacaan logis untuk kedua kueri akan sama. Itulah yang terjadi bahkan jika COALESCE dikonversi ke CASE:

Mari kita periksa rencana eksekusi. Inilah cara kita melakukannya:

  1. Jalankan pernyataan SELECT pertama dengan ekspresi COALESCE.
  2. Klik Rencana Eksekusi tab dalam hasil. Klik kanan dan pilih Simpan Rencana Eksekusi Sebagai . Dan beri nama file plan1.sqlplan .
  3. Jalankan pernyataan SELECT ke-2 dengan fungsi ISNULL.
  4. Klik Rencana Eksekusi tab dalam hasil.
  5. Klik kanan dan pilih Bandingkan Showplan .
  6. Pilih file plan1.sqlplan . Jendela baru akan muncul.

Begitulah cara kami akan memeriksa rencana eksekusi untuk semua contoh.

Kembali ke contoh pertama kita, lihat Gambar 6 untuk melihat perbandingan rencana eksekusi:

Apakah Anda memperhatikan poin-poin penting ini pada Gambar 6?

  • Bagian yang diarsir dari 2 paket (Pemindaian Indeks) berarti SQL Server menggunakan operasi yang sama untuk 2 kueri.
  • QueryPlanHash untuk 2 paket adalah 0x27CEB4CCE12DA5E7, artinya paket sama untuk keduanya.
  • Perbedaan beberapa milidetik untuk waktu yang telah berlalu dapat diabaikan.

Bawa Pulang

Ini seperti membandingkan apel dengan apel, tetapi berbeda jenis. Salah satunya adalah apel Fuji dari Jepang, yang lain adalah apel merah dari New York. Tetap saja, keduanya adalah apel.

Demikian pula, SQL Server memerlukan sumber daya yang sama dan rencana eksekusi yang dipilih untuk kedua kueri. Satu-satunya perbedaan adalah penggunaan COALESCE atau ISNULL. Perbedaan kecil, karena hasil akhirnya sama.

Contoh 2

Perbedaan besar muncul ketika Anda menggunakan subquery sebagai argumen untuk COALESCE dan ISNULL:

USE AdventureWorks
GO

SELECT COALESCE(
       (SELECT
        SUM(th.ActualCost)
        FROM Production.TransactionHistory th
        WHERE th.ProductID = 967)
       ,0) 

SELECT ISNULL(
       (SELECT
        SUM(th.ActualCost)
        FROM Production.TransactionHistory th
        WHERE th.ProductID = 967)
       ,0)

Kode di atas akan memiliki hasil yang sama, tetapi bagian dalamnya sangat berbeda.

Mari kita mulai dengan bacaan logis:

Pernyataan SELECT dengan ekspresi COALESCE memiliki dua kali lipat pembacaan logis dari pernyataan yang menggunakan ISNULL.

Tapi mengapa menggandakan pembacaan logis? Perbandingan rencana eksekusi akan mengungkapkan lebih banyak lagi:

Gambar 8 menjelaskan mengapa pembacaan logis berlipat ganda menggunakan COALESCE. Lihat 2 node Stream Agregat di rencana bawah:mereka adalah duplikat. Pertanyaan selanjutnya, kenapa diduplikasi?

Mari kita ingat kembali poin yang berkaitan dengan saat COALESCE dikonversi ke CASE. Berapa kali ekspresi dievaluasi dalam argumen? DUA KALI!

Jadi, subquery dievaluasi dua kali. Ini terlihat dalam rencana eksekusi dengan node duplikat.

Ini juga menjelaskan pembacaan logis ganda menggunakan COALESCE dibandingkan dengan ISNULL. Jika Anda berencana untuk melihat XML rencana eksekusi kueri dengan COALESCE, itu agak panjang. Tapi itu mengungkapkan bahwa subquery akan dieksekusi dua kali.

Sekarang apa? Bisakah kita mengakali ini? Tentu saja! Jika Anda pernah menghadapi hal seperti ini, yang saya yakini jarang terjadi, solusi yang mungkin adalah memecah belah dan menaklukkan. Atau, gunakan ISNULL jika hanya satu subkueri.

Cara Menghindari Mengevaluasi Ekspresi Subquery Dua Kali

Berikut cara menghindari evaluasi subquery dua kali:

  • Deklarasikan variabel dan tetapkan hasil subkueri ke dalamnya.
  • Kemudian, berikan variabel sebagai argumen ke COALESCE.
  • Ulangi langkah yang sama tergantung pada jumlah subkueri.

Seperti yang saya katakan, itu seharusnya jarang terjadi, tetapi jika itu terjadi, Anda tahu apa yang harus dilakukan sekarang.

Beberapa Kata tentang Tingkat Isolasi

Mengevaluasi subquery dua kali dapat menyebabkan masalah lain. Bergantung pada tingkat isolasi kueri Anda, hasil evaluasi pertama mungkin berbeda dari yang kedua di lingkungan multi-pengguna. Ini gila.

Untuk memastikan hasil yang stabil kembali, Anda dapat mencoba menggunakan ISOLASI SNAPSHOT. Anda juga dapat menggunakan ISNULL. Atau, itu bisa menjadi pendekatan membagi-dan-menaklukkan, seperti yang ditunjukkan di atas.

Bawa Pulang

Jadi intinya apa?

  • Selalu periksa pembacaan logis. Itu lebih penting daripada waktu yang berlalu. Gunakan waktu yang telah berlalu dan singkirkan kewarasan Anda. Mesin Anda dan server produksi akan selalu memiliki hasil yang bervariasi. Beri diri Anda istirahat.
  • Selalu periksa rencana eksekusi, jadi Anda tahu apa yang terjadi di balik layar.
  • Perhatikan bahwa ketika COALESCE diterjemahkan ke CASE, ekspresi dievaluasi dua kali. Kemudian, subquery atau yang serupa bisa menjadi masalah. Menetapkan hasil subquery ke variabel sebelum menggunakannya di COALESCE bisa menjadi solusi.
  • Yang lebih cepat bergantung pada hasil pembacaan logis dan rencana eksekusi. Tidak ada aturan umum untuk menentukan apakah COALESCE atau ISNULL lebih cepat. Jika tidak, Microsoft mungkin akan menginformasikannya, seperti yang mereka lakukan di HierarchyID dan SQL Graph.

Akhirnya, itu sangat tergantung.

Kesimpulan

Saya harap Anda memiliki bacaan yang bermanfaat untuk artikel ini. Berikut adalah poin yang kami diskusikan:

  • COALESCE adalah salah satu cara untuk menangani null. Ini adalah jaring pengaman untuk menghindari kesalahan dalam kode.
  • Ini menerima daftar argumen dan mengembalikan nilai non-null pertama.
  • Ini akan dikonversi ke ekspresi CASE selama pemrosesan kueri, tetapi tidak memperlambat kueri.
  • Meskipun ada beberapa kesamaan dengan ISNULL, ada 7 perbedaan yang mencolok.
  • Dapat digunakan dengan klausa WHERE.
  • Akhirnya, ini tidak lebih cepat atau lebih lambat dari ISNULL.

Jika Anda menyukai posting ini, tombol media sosial menunggu klik Anda. Berbagi itu peduli.

Terima kasih.

Baca juga

Menangani Nilai NULL Secara Efektif dengan Fungsi SQL COALESCE untuk Pemula

Penggunaan Praktis Fungsi SQL COALESCE


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Temukan objek yang rusak di SQL Server

  2. Menggunakan fungsi COALESCE untuk membuat nilai dipisahkan dengan koma

  3. Bagaimana DB_NAME() Bekerja di SQL Server

  4. Bagaimana cara memperbarui dua tabel dalam satu pernyataan di SQL Server 2005?

  5. sp_executesql lambat dengan parameter