Fellow MVP Jamie Thomson påpekade nyligen att det finns en "fel resultat"-bugg i SQL Server som kan visa sig när följande villkor är uppfyllda:
- Du har en indexerad vy som sammanfogar minst två tabeller;
- dessa tabeller är begränsade i endera riktningen av en främmande nyckel med en kolumn;
- du utför uppdateringar av bastabellen/tabellerna med
MERGE
som inkluderar bådeUPDATE
och (DELETE
ellerINSERT
) insatser; och, - du skickar sedan frågor som refererar till indexet på vyn (avsiktligt eller inte).
Tyvärr är Knowledge Base-artikeln som beskriver problemet (KB #2756471) ganska lätt på detaljer. De berättar inte för dig hur du ska återskapa problemet, eller ens vad, specifikt, du bör leta efter för att se om detta påverkar dig; och de nämner inte ens MERGE
(vilket faktiskt är kärnan i problemet, inte NOEXPAND
, och inte en enkel uppdatering). Det finns några ytterligare detaljer i Connect-objektet som ledde till korrigeringen; förhoppningsvis kommer KB-artikeln att uppdateras med mer information inom kort.
Under tiden kan resultatet du se är felaktig data – eller bättre uttryckt, inaktuella data :Frågan kan visa dig den gamla versionen av de uppdaterade raden/raderna! Jag tillbringade några minuter med att försöka återskapa detta scenario i AdventureWorks, och misslyckades totalt. Tack och lov skrev Paul White (blogg | @SQL_Kiwi) ett enastående inlägg som beskrev scenariot och visade en fullständig repro av problemet.
Jag tror inte att jag kan betona hur allvarligt detta är.
Miljontals kunder använder säkert indexerade vyer, många av dem har migrerat sin DML-kod för att använda MERGE
, och ett stort antal av dem finns på Enterprise Edition (eller är det inte men använder NOEXPAND
ledtråd eller hänvisar direkt till indexet). Paul var snabb med att påpeka att NOEXPAND
krävs inte för att reproducera problemet i Enterprise Edition, och upptäckte också många av de andra detaljerna som krävs för att reproducera felet.
Detta inlägg är inte avsett att stjäla någon åska från Jamies eller Pauls inlägg; bara ett försök att upprepa oron och öka medvetenheten om denna fråga. Om du har för vana att ignorera kumulativa uppdateringar, väljer att vänta på Service Pack och det finns någon chans att det här problemet kan påverka dig just nu, är du skyldig dig själv, för att inte tala om dina intressenter och kunder, att ta denna fråga på allvar.
Så vad ska du göra?
Nåväl, vad du gör härnäst beror på vilken version och utgåva av SQL Server du kör, och om felet faktiskt påverkar dig (eller skulle kunna).
- Du bör uppdatera till den senaste kumulativa uppdateringen för din filial:
Branch Fast i CU Bygg Minsta version krävs
för att tillämpa uppdateringKB-artikel
(nedladdning)2008 Service Pack 3 CU #8 10.00.5828 10.00.5500 KB #2771833 2008 R2 Service Pack 1 CU #10 10.50.2868 10.50.2500 KB #2783135 2008 R2 Service Pack 2 CU #4 10.50.4270 10.00.4000 KB #2777358 2012 RTM CU #5 11.00.2395 11.00.2100 KB #2777772 2012 Service Pack 1 CU #2 11.00.3339 11.00.3000 KB #2790947 Tabell 1 :Bygger som innehåller korrigeringen
- Om du inte tillämpar korrigeringen måste du testa alla referenser till dina vyer för att validera att de ger korrekta resultat i alla fall – inklusive efter att du har uppdaterat bastabellerna med
MERGE . Om de inte gör det (eller om du misstänker att de senare kan påverkas), bör du bygga om det klustrade indexet på alla berörda vyer (eller reparera de indexerade vyerna med
DBCC CHECKTABLE
, som Paul har beskrivit i sitt inlägg), och sluta användaMERGE
mot dessa tabeller tills du har tillämpat korrigeringen. Om du fortsätter att användaMERGE
mot bastabellerna, förbered dig på att fortsätta reparera vyerna för att undvika problemet.
- En snabbare lösning skulle vara att förhindra att den skadade indexerade vyn överhuvudtaget används, genom att använda någon av följande metoder som krävs:
- tillämpa frågetipset
ALTERNATIV (EXPANDERA VISNINGAR)
till alla relevanta frågor; - ta bort alla explicita referenser till indexet på vyn;
- i standardutgåvor eller andra utgåvor där indexerade vyer inte matchas automatiskt, ta bort alla instanser av
NOEXPAND
.
Men detta skulle naturligtvis till stor del motverka syftet med den indexerade vyn – kan lika gärna släppa indexet. Som sagt, det är oftast bättre att få rätt resultat långsamt, än att få fel resultat snabbt; så det kanske är okej.
- tillämpa frågetipset
SQL Server 2008 SP3
SQL Server 2008 R2 SP1/SP2
SQL Server 2012 RTM/SP1
Dina alternativ om du använder en av dessa versioner:
SQL Server 2008 RTM/SP1/SP2
SQL Server 2008 R2 RTM
Tyvärr är du på en version som inte längre finns i mainstream-stöd, och det är osannolikt att det här problemet kommer att lösas för dig (såvida du inte har utökat stöd och du gör mycket oväsen). Så dina alternativ är begränsade här – antingen flytta till en gren som stöds enligt tabellen ovan och tillämpa den kumulativa uppdateringen, eller välj ett av de andra alternativen som nämnts tidigare.
SQL Server 2000
SQL Server 2005
Tja, de dåliga nyheterna är att du också har en version som inte längre stöds. Den goda nyheten är att i det här specifika fallet spelar det ingen roll – du kan inte använda MERGE
hur som helst, så det här felet kan inte påverka dig.
Andra MERGE-problem
Tyvärr är detta långt ifrån den första buggen vi har sett med MERGE
, och det kommer förmodligen inte att vara den sista. Här är ett snabbt urval av ett dussin SAMMANFATTNING
buggar som fortfarande är markerade som aktiva på Connect:
- #773895 :MERGE rapporterar felaktigt unika nyckelöverträdelser
- #766165 :MERGE utvärderar filtrerat index per rad, inte efter operation, vilket orsakar filtrerat indexöverträdelse
- #723696 :Grundläggande MERGE-uppslagning som orsakar låsningar
- #713699 :En kontroll av systempåståenden har misslyckats ("cxrowset.cpp":1528)
- #699055 :SAMMANFATTNING av frågeplaner tillåter överträdelser av FK- och CHECK-begränsningar
- #685800 :Parametriserad DELETE och MERGE Tillåt överträdelser av främmande nyckelbegränsningar
- #654746 :sammanslagning i SQL2008 SP2 lider fortfarande av "Försök att ställa in en icke-NULL-bar kolumns värde till NULL"
- #635778 :NOT MATCHED och MATCHED delar av en SQL MERGE-sats är inte optimerade
- #633132 :SLUT TILL MED FILTERAD KÄLLA fungerar inte korrekt
- #596086:MERGE-satsfel när INSERT/DELETE används och filtrerat index
- #583719 :MERGE-satsen behandlar icke-nullbara beräknade kolumner felaktigt i vissa scenarier
- #539084 :MERGE Stmt :Sökvillkor i en icke-nyckelkolumn och en ORDER BY i källhärledd tabell bryter MERGE fullständigt
Nu kan det vara så att några av dessa buggar faktiskt har åtgärdats, men deras status är fel eftersom slingan tillbaka till Connect inte har stängts. Även om så är fallet kan det inte vara sant för dem alla (och eventuellt för andra som jag inte upptäckte).
Dessutom har det visat sig av Dan Guzman att SAMMANSLUTNING
är inte immun mot rasförhållanden och andra samtidiga problem. Lösningen är att använda HOLDLOCK
(eller en högre isoleringsnivå); det är dock en vanlig missuppfattning att SAMMANSLUTNING
är helt atomär och inte alls utsatt för detta problem. Därför undrar jag högt:hur många MERGE
uttalanden där ute inkluderar HOLDLOCK
(eller körs under SERIALIZABLE
)? Hur många har noggrant testats för frågor som rör samtidighet?
Slutsats
Personligen tycker jag att syntaxen är bra (även om det är skrämmande att lära sig), men varje gång ett problem dyker upp urholkar det mitt förtroende för det praktiska i att ersätta befintlig DML med den nya konstruktionen.
Med det i åtanke, att inte vara Chicken Little, men jag skulle inte känna mig bekväm med att rekommendera någon att använda MERGE
såvida de inte implementerar extremt omfattande tester. Vissa av dessa problem finns också med standard UPSERT
metoder, men problemen är mer uppenbara där. SAMMANFATTNING
, bara genom sin natur med ett påstående, gör att du vill tro på magi. Kanske en dag kommer det att leverera, men just nu vet jag att det inte kommer att kunna såga en person på mitten utan någon seriös hjälp.