Indeks pada kolom yang dihitung tetap tidak dapat dicari

15

Saya punya tabel, dipanggil Address, yang memiliki kolom yang dihitung tetap disebut Hashkey. Kolom bersifat deterministik tetapi tidak tepat. Ini memiliki indeks unik di atasnya yang tidak dapat dicari. Jika saya menjalankan kueri ini, mengembalikan kunci utama:

SELECT @ADDRESSID= ISNULL(AddressId,0)
FROM dbo.[Address]
WHERE HashKey = @HashKey

Saya mendapatkan rencana ini:

BasicPlan

Jika saya memaksakan indeks saya mendapatkan rencana yang lebih buruk ini:

ForceIndex

Jika saya mencoba dan memaksa indeks dan pencarian, saya mendapatkan kesalahan:

Prosesor kueri tidak dapat menghasilkan rencana kueri karena petunjuk yang ditentukan dalam kueri ini. Kirim ulang kueri tanpa menentukan petunjuk dan tanpa menggunakanSET FORCEPLAN

Apakah ini hanya karena itu tidak tepat? Saya pikir itu tidak masalah jika itu bertahan?

Apakah ada cara untuk membuat indeks ini dapat dicari tanpa menjadikan ini kolom yang tidak dihitung?

Adakah yang punya tautan ke informasi tentang ini?

Saya tidak dapat memposting pembuatan tabel yang sebenarnya, tetapi di sini adalah tabel uji yang memiliki masalah yang sama:

drop TABLE [dbo].[Test]

CREATE TABLE [dbo].[Test]
  (
     [test]        [VARCHAR](100) NULL,
     [TestGeocode] [geography] NULL,
     [Hashkey] AS CAST(
                        ( hashbytes
                            ('SHA', 
                                ( RIGHT(REPLICATE(' ', (100)) + isnull([test], ''), ( 100 )) ) 
                                + RIGHT(REPLICATE(' ', (100)) + isnull([TestGeocode].[ToString](), ''), ( 100 ))
                            ) 
                        ) AS BINARY(20)                                                                                                        
                      ) PERSISTED
    CONSTRAINT [UK_Test_HashKey] UNIQUE NONCLUSTERED([Hashkey])
  )    
GO    
DECLARE @Hashkey BINARY(20)

SELECT [Hashkey]
FROM   [dbo].[Test] WITH (FORCESEEK) /*Query processor could not produce a query plan*/
WHERE  [Hashkey] = @Hashkey 
Paul White Reinstate Monica
sumber

Jawaban:

12

Masalahnya tampaknya terkait dengan fakta yang [TestGeocode].[ToString]()mengembalikan maxtipe data ( nvarchar(max)).

Saya juga menghadapi masalah dengan versi yang lebih sederhana ini (mengubah definisi c1menjadi varchar(8000)atau menggunakan COALESCEalih-alih ISNULLmenyelesaikannya)

DROP TABLE dbo.Test

CREATE TABLE dbo.Test
  (
     c1        VARCHAR(
                          MAX    --Fails
                        --  8000 --Works fine
                          ) NULL,
     comp1 AS CAST(ISNULL(c1, 'ABC') AS VARCHAR(100))
    CONSTRAINT UK_Test_comp1 UNIQUE NONCLUSTERED(comp1)
  )

GO

DECLARE @comp1 VARCHAR(100)

SELECT comp1
FROM   dbo.Test WITH (FORCESEEK)
WHERE  comp1 = @comp1 
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8606); 

Referensi kolom yang dihitung diperluas ke definisi yang mendasarinya kemudian dicocokkan kembali ke kolom nanti. Ini memungkinkan kolom yang dikomputasi dicocokkan tanpa merujuknya dengan nama sama sekali dan juga memungkinkan penyederhanaan untuk beroperasi pada definisi yang mendasarinya.

ISNULLmengembalikan tipe data dari parameter pertama ( VARCHAR(MAX)dalam contoh saya). Jenis pengembalian COALESCEakan ada di VARCHAR(MAX)sini juga tetapi tampaknya dievaluasi secara berbeda dengan cara yang menghindari masalah.

Dalam kasus di mana kueri berhasil, output flag trace mencakup yang berikut ini

ScaOp_Convert varchar(max) collate 49160,Null,Var,Trim,ML=65535

    ScaOp_Const TI(varchar collate 49160,Var,Trim,ML=3) 
                      XVAR(varchar,Owned,Value=Len,Data = (3,ABC))

Jika gagal ini diganti oleh

ScaOp_Identifier COL: ConstExpr1003 

Saya berspekulasi bahwa dalam kasus di mana gagal (implisit) CAST('ABC' AS VARCHAR(MAX))hanya dilakukan sekali dan ini dievaluasi sebagai konstanta runtime ( informasi lebih lanjut ). Namun referensi ke label konstanta runtime ini, alih-alih nilai literal string itu sendiri, mencegahnya agar tidak cocok dengan definisi kolom yang dihitung.

Penulisan ulang ini menghindari masalah dalam permintaan Anda

CREATE TABLE [dbo].[Test]
  (
     [test]        [VARCHAR](100) NULL,
     [TestGeocode] [geography] NULL,
     [Hashkey] AS CAST(
                        ( hashbytes
                            ('SHA', 
                                ( RIGHT(SPACE(100) + isnull([test], ''), 100) ) 
                                + RIGHT(SPACE(100) + isnull(CAST(RIGHT([TestGeocode].[ToString](),100) AS VARCHAR(100)), ''),100)
                            ) 
                        ) AS BINARY(20)                                                                                                        
                      ) PERSISTED
    CONSTRAINT [UK_Test_HashKey] UNIQUE NONCLUSTERED([Hashkey])
  )
Martin Smith
sumber
0

Anda akan mendapatkan gejala-gejala ini karena ekspresi non-sargable jika tipe data @HashKeytidak cocok dengan yang diindeks kolom. Anda mungkin memerlukan eksplisit CASTdalam ekspresi kolom yang dihitung untuk memaksa tipe data yang diinginkan.

Berdasarkan repro Anda, saya menduga ini adalah bug. Saya mengajukan bug Connect, Computed Column Index Not Used , dengan versi solusi Martin juga. Jangan ragu untuk memilih.

Dan Guzman
sumber