SQL Server Query Plan XML: Panjang QueryPlanHash

11

UPDATE: Ini pasti bug. Untuk detail selengkapnya, lihat Barang Sambung ini .

Saat menguji beberapa perubahan pada sp_BlitzCache (pengungkapan penuh, saya adalah salah satu penulis), saya menemukan apa yang saya pikir adalah bug dalam kode kami.

Pada satu titik, kami mencocokkan Hash Paket Kueri untuk mendapatkan biaya permintaan. Kami melakukannya seperti:

statement.value('sum(/p:StmtSimple[xs:hexBinary(substring(@QueryHash, 3)) =
    xs:hexBinary(sql:column("b.QueryHash"))]/@StatementSubTreeCost)', 'float')

Sejauh ini yang saya lihat, ini berhasil. Namun, dalam satu kasus aneh, substring di XML melempar NULLnilai, dan rencana itu menunjukkan biaya 0, meskipun itu agak tinggi.

Menggali rencana eksekusi (pengungkapan penuh, saya bekerja untuk perusahaan yang menyelenggarakan Tempel Paket), saya perhatikan bahwa Query Plan Hash untuk hash satu masalah adalah 17 karakter, sedangkan sisanya adalah 18 karakter. Berikut adalah contohnya:

QueryPlanHash = "0x4410B0CA640CDA89"
QueryPlanHash = "0x2262FEA4CE645569" 
QueryPlanHash = "0xED4F225CC0E97E5" - Masalah!
QueryPlanHash = "0xBF878EEE6DB955EA"
QueryPlanHash = "0x263B53BC8C14A452"
QueryPlanHash = "0x89F5F146CF4B476F"
QueryPlanHash = "0xEF47EA40805C8961"
QueryPlanHash = "0xB7BE27D6E43677A5"
QueryPlanHash = "0x815C54EC43A6A6E9"

Query Plan Hash terdaftar sebagai a BINARY 8- mungkin ini harus selalu sama panjangnya, tetapi apa yang diketahui orang seperti saya tentang nilai-nilai biner?

Bermain dengan XQuery sedikit, saya menemukan bahwa dengan mengubah substring untuk memulai di posisi kedua, itu akan muncul dengan nilai hash yang valid (meskipun salah).

WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p)
SELECT   
        QueryPlanCost = statement.value('sum(/p:StmtSimple/@StatementSubTreeCost)', 'float'),
        **q.n.value('substring(@QueryPlanHash, 2)', 'BINARY(8)')**
FROM    #statements s
CROSS APPLY s.statement.nodes('/p:StmtSimple') AS q(n)
OPTION(RECOMPILE);

WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p)
SELECT   
        QueryPlanCost = statement.value('sum(/p:StmtSimple/@StatementSubTreeCost)', 'float'),
        **q.n.value('substring(@QueryPlanHash, 3)', 'BINARY(8)')**
FROM    #statements s
CROSS APPLY s.statement.nodes('/p:StmtSimple') AS q(n)
OPTION(RECOMPILE);

Gila

Saya menjalankan SQL Server 2016, SP1 (13.0.4001).

Adakah yang pernah mengalami ini sebelumnya?

Apakah 17 karakter panjang yang valid untuk suatu BINARY 8nilai?

Apakah ini terlihat seperti bug yang seharusnya mendapatkan item Connect?

Erik Darling
sumber

Jawaban:

11

Saya pikir ini terjadi karena satu hash adalah jumlah karakter yang ganjil. Valid VARBINARYakan perlu memiliki "pasangan" genap untuk merepresentasikan data dengan benar. Jadi ... Anda harus dapat menyelesaikan ini dengan menghapus 0x, menempatkan '0' di awal, meraih 18 karakter yang tepat, dan kemudian melemparkannya ke VARBINARY.

CONVERT(VARBINARY(MAX), RIGHT('0' + SUBSTRING('0xED4F225CC0E97E5', 3, 20), 18), 2)

Jika Anda menginginkan sesuatu yang lebih kuat, semoga berhasil, karena Anda harus membaginya dengan 2 sebagai bilangan bulat, dan mendapatkan modulo 2, dan kemudian "lakukan hal yang benar" untuk mengetahui seberapa besar data Anda seharusnya.

Jeremiah Peschka
sumber