Repro Scénario:
CREATE TABLE test (
ID int IDENTITY(1,1),
mykey nvarchar(255) NOT NULL,
exp_date datetime,
PRIMARY KEY (ID));
GO
CREATE INDEX not_expired_keys ON test (exp_date, mykey);
INSERT INTO test (mykey, exp_date) VALUES ('A', NULL);
Je commence la transaction 1:
-- add key B
BEGIN TRANSACTION;
INSERT INTO test (mykey, exp_date) VALUES ('B', NULL);
...
puis exécuter une transaction 2 en parallèle:
-- expire key A
BEGIN TRANSACTION;
UPDATE test SET exp_date = GETDATE() WHERE exp_date IS NULL AND mykey = 'A'; -- <-- Blocking
ROLLBACK;
Comme il s'avère, la mise à jour d'insertion non engagée de transaction 1 est la mise à jour de la transaction 2, même s'ils affectent des ensembles disjoints de lignes (mykey = 'B'
vs. mykey = 'A'
).
Observations:
READ UNCOMMITTED
.mykey
. Malheureusement, je ne peux pas faire cela, car les noms de clés peuvent être réutilisés une fois qu'une clé a expiré.Mes questions:
(Hors de curiosité :) Pourquoi ces déclarations se bloquent-elles même sur le READ UNCOMMITTED
niveau?
Y a-t-il un moyen facile et fiable de ne pas les bloquer?
Permet de jeter un coup d'œil sur les plans d'exécution.
1ère requête - insert
BEGIN TRANSACTION;
INSERT INTO test (mykey, exp_date) VALUES ('B', NULL);
Nous voyons que SQL Server effectue une opération d'insertion d'index en cluster.
Permet maintenant de jeter un coup d'oeil sur la mise à jour
BEGIN TRANSACTION;
UPDATE test
SET exp_date = GETDATE()
WHERE exp_date IS NULL AND mykey = 'A' -- <-- Blocking
SQL Server scanne l'index en cluster de la table et mettez-le, même s'il peut choisir un autre index pour trouver les lignes correspondantes. La raison en est, car nous n'avons qu'une ligne dans la table et que SQL Server Optimizer cherche plus facilement à numériser l'index en clustere au lieu de rechercher des données dans l'index non en cluster.
Mais que si nous forçions le serveur SQL à utiliser un index non clustered?
BEGIN TRANSACTION;
UPDATE test
SET exp_date = GETDATE()
FROM test WITH(INDEX = not_expired_keys)
WHERE exp_date IS NULL AND mykey = 'A' -- <-- No Blocking!!!
Je pense que si nous mettons davantage de lignes dans la table SQL Server choisira l'index non clustered pour la recherche des lignes qui doivent être mises à jour et qu'il n'y aura pas de blocage.