ดัชนีในคอลัมน์ที่คำนวณแล้วยังไม่สามารถค้นหาได้


15

ฉันมีตารางเรียกว่ามีคอลัมน์คำนวณยังคงเรียกว่าAddress Hashkeyคอลัมน์นั้นถูกกำหนดไว้แล้ว แต่ไม่แม่นยำ มันมีดัชนีที่เป็นเอกลักษณ์ของมันที่ไม่สามารถหาได้ ถ้าฉันเรียกใช้แบบสอบถามนี้คืนคีย์หลัก:

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

ฉันได้รับแผนนี้:

BasicPlan

ถ้าฉันบังคับดัชนีฉันจะได้รับสิ่งนี้ยิ่งแย่ลง:

ForceIndex

ถ้าฉันพยายามและบังคับทั้งดัชนีและการค้นหาฉันได้รับข้อผิดพลาด:

ตัวประมวลผลแบบสอบถามไม่สามารถสร้างแผนแบบสอบถามได้เนื่องจากคำแนะนำที่กำหนดไว้ในแบบสอบถามนี้ ส่งแบบสอบถามอีกครั้งโดยไม่ระบุคำแนะนำใด ๆ และไม่ใช้SET FORCEPLAN

นี่เป็นเพียงเพราะมันไม่แม่นยำใช่ไหม ฉันคิดว่าไม่สำคัญว่ามันจะยังคงอยู่หรือไม่?

มีวิธีทำให้ดัชนีนี้ค้นหาได้โดยไม่ทำให้คอลัมน์นี้ไม่คำนวณหรือไม่

ใครบ้างมีลิงค์ไปยังข้อมูลเกี่ยวกับเรื่องนี้?

ฉันไม่สามารถโพสต์การสร้างตารางจริง แต่นี่เป็นตารางทดสอบที่มีปัญหาเดียวกัน:

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 

คำตอบ:


12

ดูเหมือนว่าปัญหาจะเกี่ยวข้องกับข้อเท็จจริงที่[TestGeocode].[ToString]()ส่งกลับmaxประเภทข้อมูล ( nvarchar(max))

ฉันยังพบปัญหากับรุ่นที่ง่ายกว่านี้ (เปลี่ยนคำจำกัดความc1เป็นvarchar(8000)หรือใช้COALESCEแทนISNULLแก้ไข)

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); 

การอ้างอิงคอลัมน์ที่คำนวณแล้วจะขยายออกไปเป็นคำจำกัดความพื้นฐานจากนั้นจับคู่กลับไปที่คอลัมน์ในภายหลัง สิ่งนี้จะช่วยให้คอลัมน์ที่คำนวณถูกจับคู่โดยไม่อ้างอิงพวกเขาด้วยชื่อเลยและยังช่วยให้การทำให้ง่ายขึ้นในการดำเนินการตามคำจำกัดความพื้นฐาน

ISNULLส่งกลับประเภทข้อมูลของพารามิเตอร์แรก ( VARCHAR(MAX)ในตัวอย่างของฉัน) ประเภทส่งคืนของCOALESCEจะอยู่VARCHAR(MAX)ที่นี่ด้วย แต่ดูเหมือนว่าจะได้รับการประเมินแตกต่างกันในวิธีที่หลีกเลี่ยงปัญหา

ในกรณีที่แบบสอบถามประสบความสำเร็จเอาต์พุตการติดตามสถานะรวมถึงต่อไปนี้

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))

มันจะถูกแทนที่ด้วยที่ไหน

ScaOp_Identifier COL: ConstExpr1003 

ฉันคาดการณ์ว่าในกรณีที่มันล้มเหลว (โดยปริยาย) CAST('ABC' AS VARCHAR(MAX))จะทำเพียงครั้งเดียวและนี่จะถูกประเมินว่าเป็นค่าคงที่รันไทม์ ( ข้อมูลเพิ่มเติม ) อย่างไรก็ตามการอ้างอิงไปยังเลเบลค่าคงที่รันไทม์นี้แทนที่จะเป็นค่าตัวอักษรสตริงจริงป้องกันไม่ให้ตรงกับคำจำกัดความคอลัมน์ที่คำนวณ

การเขียนซ้ำนี้จะหลีกเลี่ยงปัญหาในการสืบค้นของคุณ

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])
  )

0

คุณจะได้รับอาการเหล่านี้เนื่องจากนิพจน์ที่ไม่สามารถโต้แย้งได้หากประเภทข้อมูลของ@HashKeyไม่ตรงกับคอลัมน์ในดัชนี คุณอาจต้องการชัดเจนCASTในนิพจน์คอลัมน์ที่คำนวณเพื่อบีบบังคับชนิดข้อมูลที่ต้องการ

จากข้อสงสัยของคุณฉันคิดว่านี่เป็นข้อผิดพลาด ฉันยื่นข้อผิดพลาดในการเชื่อมต่อดัชนีคอลัมน์ที่คำนวณแล้วไม่ได้ใช้พร้อมกับวิธีแก้ปัญหาของ Martin เช่นกัน รู้สึกอิสระที่จะลงคะแนน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.