sql >> Database teknologi >  >> RDS >> Sqlserver

Hvorfor er denne forespørgsel langsom første gang, efter jeg har startet tjenesten?

Jeg kan kunne også gengive dette 100% af tiden på min maskine. (se note til sidst)

Kernen i problemet er, at du tager S ud låser på systemtabelrækker i tempdb der kan være i konflikt med de låse, der er nødvendige for intern tempdb oprydningstransaktioner.

Når dette oprydningsarbejde allokeres til den samme session, som ejer S lås et ubestemt hæng kan forekomme.

For at undgå dette problem med sikkerhed skal du stoppe med at referere til systemet objekter inde i tempdb .

Det er muligt at oprette en taltabel uden at referere til eksterne tabeller overhovedet. Følgende skal ikke læse nogen basistabelrækker og tager derfor heller ingen låse.

Med Ti(N) AS (VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1) SELECT TOP 1000000 IDENTITY(INT, 1, 1) NumberINTO NumbersFROM Ti T10, Ti T100, Ti T1000, Ti T10000, Ti T100000, Ti T1000000

Trin til gengivelse

Opret først en procedure

OPRET PROC PAS SET NOCOUNT ON; DECLARE @T TABLE (X INT)GO 

Genstart derefter SQL Service og udfør i én forbindelse

MENS IKKE FINDER(SELECT * FROM sys.dm_os_waiting_tasks WHERE session_id =blocking_session_id) BEGIN /*Dette vil forårsage de problematiske droptemp-transaktioner*/ EXEC sp_rekompilere 'P' EXEC P END;SELECT *FROM sys.dm_taskWit blocking_session_id  

Kør derefter i en anden forbindelse

BRUG tempdb;SELECT TOP 1000000 IDENTITY(INT, 1, 1) NumberINTO #TFROM sys.objects s1CROSS JOIN sys.objects s2CROSS JOIN sys.objects s3CROSS JOIN sys.objects TABLEDROP #TABLEDROP #TABLEDROP s4;> 

Forespørgslen, der udfylder Numbers-tabellen, ser ud til at lykkes med at komme ind i en live-lås-situation med de interne systemtransaktioner, der rydder op i midlertidige objekter såsom tabelvariabler.

Det lykkedes mig at få blokeret session-id 53 på denne måde. Den er blokeret på ubestemt tid. Outputtet af sp_WhoIsActive viser, at denne edderkop tilbringer næsten hele tiden suspenderet. I fortløbende kørsler tallene i reads kolonne stiger, men værdierne i de andre kolonner forbliver stort set de samme.

Ventetiden viser ikke et stigende mønster, men det indikerer, at blokeringen skal ophæves med jævne mellemrum, før den blokeres igen.

VÆLG *FRA sys.dm_os_waiting_tasksWHERE session_id =blocking_session_id 

Returnerer

+----------------------+-----------+------- ----------+------------------+-----------+-------- --------------+-------------------------+------------- ---------------------------------------+-------------- -------------------------------------------------- ----------------------------------+| venter_opgave_adresse | session_id | exec_context_id | wait_duration_ms | vente_type | ressource_adresse | blokeringsopgaveadresse | blocking_session_id | blocking_exec_context_id | resource_description |+----------------------+------------+----------- ------+-------------------+------------+------- --------------------------------------+------------------- ----+---------------------------+------------------- -------------------------------------------------- ------------------------------------+| 0x00000002F2C170C8 | 53 | 0 | 86 | LCK_M_X | 0x00000002F9B13040 | 0x00000002F2C170C8 | 53 | NULL | keylock hobtid=281474978938880 dbid=2 id=lock2f9ac8880 mode=U associeretObjectId=281474978938880 |+-----------------+--------- ---+----------------+------------------------+--------- --+--------------------+----------------------+-- ------------------+---------------------------+--- -------------------------------------------------- ----------------------------------------------------+

Brug af id'et i ressourcebeskrivelsen

SELECT o.nameFROM sys.allocation_units au MED (NOLOCK) INNER JOIN sys.partitions p MED (NOLOCK) ON au.container_id =p.partition_id INNER JOIN sys.all_objects o MED (NOLOCK) ON o.object_id =p.object_idWHERE allocation_unit_id =281474978938880  

Returnerer

+-------------+| navn |+------------+| sysschobjs |+------------+

Kører

SELECT resource_description,request_statusFROM sys.dm_tran_locks WHERE request_session_id =53 OG request_status <> 'GANT' 

Returnerer

+-----------------------------+----------------+| ressourcebeskrivelse | request_status |+----------------------+----------------+| (246708db8c1f) | KONVERTER |+-----------------------------+----------------+

Tilslutter via DAC'en og kører

VÆLG id,navnFRA tempdb.sys.sysschobjs MED (NOLOCK)WHERE %%LOCKRES%% ='(246708db8c1f)'  

Returnerer

+-------------+-----------+| id | navn |+-------------+-----------+| -1578606288 | #A1E86130 |+-------------+-----------+

Nysgerrig efter hvad det er

SELECT name,user_type_idFROM tempdb.sys.columnsWHERE object_id =-1578606288  

Returnerer

+------+--------------+| navn | user_type_id |+------+----------------+| X | 56 |+------+--------------+

Dette er kolonnenavnet i tabelvariablen, der bruges af den lagrede proc.

Kører

SELECT request_mode, request_status, request_session_id, request_owner_id, lock_owner_address, t.transaction_id, t.name, t.transaction_begin_timeFROM sys.dm_tran_locks l JOIN sys.dm_tran_active_transactionsrequest =transaction_ownert_ON l.cHEREd_ON l.bHEREt_ON l.bHEREt_ON l. )'  

Returnerer

+--------------+----------------+----------- ----------+-------------------+--------------------+ --------------+-------------+--------------------- ------+| request_mode | request_status | request_session_id | request_owner_id | låseejeradresse | transaktions-id | navn | transaktions_begyndelsestidspunkt |+--------------+----------------+-------------- -----+------------------+--------------------+---- --------------+-------------+----------------------- --+| U | TILSKUD | 53 | 227647 | 0x00000002F1EF6800 | 227647 | droptemp | 24-11-2013 18:36:28.267 || S | TILSKUD | 53 | 191790 | 0x00000002F9B16380 | 191790 | VÆLG TIL | 24-11-2013 18:21:30.083 || X | KONVERTER | 53 | 227647 | 0x00000002F9B12FC0 | 227647 | droptemp | 2013-11-24 18:36:28.267 |+-------------------+----------------+------ --------------+------------------------+---------------- ----+----------------+--------------+-------- -----------+

SELECT INTO transaktionen indeholder en S lås på rækken i tempdb.sys.sysschobjs vedrørende tabelvariablen #A1E86130 . droptemp transaktionen kan ikke få et X lås på denne række på grund af denne modstridende S lås.

At køre denne forespørgsel gentagne gange afslører, at transaction_id for droptemp transaktionen ændres gentagne gange.

Jeg spekulerer i, at SQL Server skal allokere disse interne transaktioner på brugerspidser og prioritere dem, før de udfører brugerarbejdet. Så sessions-id 53 sidder fast i en konstant cyklus, hvor den starter en droptemp transaktion, blokeres af brugertransaktionen, der kører på samme spid. Ruller den interne transaktion tilbage og gentager derefter processen på ubestemt tid.

Dette bekræftes ved at spore de forskellige låse- og transaktionsbegivenheder i SQL Server Profiler, efter at spiden er blevet hængt.

Jeg sporede også låsebegivenhederne forud for det.

Lås hændelsesblokering

De fleste af de delte nøglelåse fjernes af SELECT INTO transaktion på nøgler i sysschobjs blive løsladt med det samme. Undtagelsen er den første lås på (246708db8c1f) .

Dette giver mening, da planen viser indlejrede loops-scanninger af [sys].[sysschobjs].[clst] [o] og fordi midlertidige objekter får negative objektider, vil de være de første rækker, der stødes på i scanningsrækkefølge.

Jeg stødte også på den situation, der er beskrevet i OP, hvor at køre en trevejs krydsforbindelse først ser ud til at tillade, at den firevejs ene kan lykkes.

De første par hændelser i sporet for SELECT INTO transaktion er der et helt andet mønster.

Dette var efter en genstart af tjenesten, så låseressourceværdierne i tekstdatakolonnen er ikke direkte sammenlignelige.

I stedet for at fastholde låsen på den første nøgle og derefter et mønster med at erhverve og frigive efterfølgende nøgler, ser det ud til at erhverve mange flere låse uden at frigive dem i starten.

Jeg formoder, at der må være en vis variation i udførelsesstrategien, der undgår problemet.

Opdater

Det Connect-element, jeg rejste om dette er ikke blevet markeret som rettet, men jeg er nu på SQL Server 2012 SP2 og kan nu kun reproducere midlertidig selvblokering i stedet for permanent. Jeg får stadig selvblokering, men efter nogle mislykkede forsøg på at udføre droptemp transaktionen med succes ser ud til at gå tilbage til behandling af brugertransaktionen. Derefter udføres systemtransaktionen med succes. Stadig på samme spids. (otte forsøg i et eksempel. Jeg er ikke sikker på, om dette vil blive gentaget konsekvent)



  1. Er det sandt, at jeg ikke kan redigere en MySQL-trigger, jeg er nødt til at droppe den og oprette en ny?

  2. psql:FATAL:for mange forbindelser til rollen

  3. Er det muligt at definere en tidsstempelkolonne, der ikke er null og ikke har nogen standard og ingen speciel adfærd ved opdatering?

  4. Sådan forhindrer du forbindelsestimeout for store MySQL-importer