İşlemleri Kullanmama ve Birini Taklit Etmek İçin Bir Geçici Çözüm Kullanma


43

Birkaç yıldan beri T-SQL geliştiriyorum ve her zaman daha fazla kazıyorum, dilin tüm yönleriyle ilgili elimden geldiğince öğrenmeye devam ediyorum. Geçenlerde yeni bir şirkette çalışmaya başladım ve işlemler hakkında garip bir öneri olduğunu düşündüğüm şeyi aldım. Onları asla kullanma. Bunun yerine, bir işlemi simüle eden bir geçici çözüm kullanın. Bu, bir çok işlem ve ardından çok fazla engelleme olan tek bir veritabanında çalışan DBA'mızdan geliyor. Öncelikle çalıştığım veritabanı bu sorundan muzdarip değil ve geçmişte işlemlerin kullanıldığını görüyorum.

Yapmayı engellemenin, doğası gereği olduğu gibi işlemlerle yapılmasının beklendiğini ve birini kullanmadan kurtulabiliyorsanız, elbette bunu yapın. Ancak her ifadenin başarılı bir şekilde yürütülmesi gereken birçok durum var. Biri başarısız olursa hepsinin yerine getirmemesi gerekir.

İşlemlerimin kapsamını her zaman olabildiğince dar, her zaman SET XACT_ABORT ON ile birlikte ve her zaman bir TRY / CATCH içinde kullandım.

Örnek:

CREATE SCHEMA someschema;
GO


CREATE TABLE someschema.tableA
(id   INT NOT NULL IDENTITY(1, 1) PRIMARY KEY, 
 ColA VARCHAR(10) NOT NULL
);
GO

CREATE TABLE someschema.tableB
(id   INT NOT NULL IDENTITY(1, 1) PRIMARY KEY, 
 ColB VARCHAR(10) NOT NULL
); 
GO


CREATE PROCEDURE someschema.ProcedureName @ColA VARCHAR(10), 
                                          @ColB VARCHAR(10)
AS
SET NOCOUNT, XACT_ABORT ON;
BEGIN
BEGIN TRY
    BEGIN TRANSACTION;

    INSERT INTO someschema.tableA(ColA)
    VALUES(@ColA);

    INSERT INTO someschema.tableB(ColB)
    VALUES(@ColB);

--Implement error
    SELECT 1/0 

    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF @@trancount > 0
    BEGIN
        ROLLBACK TRANSACTION;
    END;
    THROW;
    RETURN;
END CATCH;
END;
GO

İşte benim yapmamı önerdikleri şey.

GO



CREATE PROCEDURE someschema.ProcedureNameNoTransaction @ColA VARCHAR(10), 
                                                       @ColB VARCHAR(10)
AS
SET NOCOUNT ON;
BEGIN
BEGIN TRY
    DECLARE @tableAid INT;
    DECLARE @tableBid INT;

    INSERT INTO someschema.tableA(ColA)
    VALUES(@ColA);
    SET @tableAid = SCOPE_IDENTITY();

    INSERT INTO someschema.tableB(ColB)
    VALUES(@ColB);
    SET @tableBid = SCOPE_IDENTITY();

--Implement error
    SELECT 1/0 

END TRY
BEGIN CATCH
    DELETE FROM someschema.tableA
    WHERE id = @tableAid;

    DELETE FROM someschema.tableB
    WHERE id = @tableBid;

    THROW;

    RETURN;
END CATCH;
END;
GO

Topluma olan sorum şu şekilde. Bu, işlemler için uygun bir geçici çözüm olarak mantıklı geliyor mu?

İşlemler hakkında bildiklerimden ve çözümün önerdiği şeyden kanaatim, hayır, bu uygulanabilir bir çözüm değil ve birçok başarısızlık noktası ortaya koyuyor.

Önerilen geçici çözümde, gerçekleşen dört örtük işlem görüyorum. Iki denemede ekler ve sonra catch içindeki silmeler için iki işlem daha yapılır. Uçları “geri alır” ama hiçbir şeyi geri almadan bu yüzden hiçbir şey geri alınmaz.

Bu, önerdikleri kavramı göstermek için çok temel bir örnektir. Bunu yapmakta olduğum gerçek saklı prosedürlerden bazıları onları çok uzun ve yönetmeleri zorlaştırıyor çünkü çoklu sonuç kümelerinin “geri alınması” bu örnekte iki parametre değerinin tahmin edebileceğiniz gibi oldukça karmaşık bir hal alıyor. "Geri alma" şu anda manuel olarak yapıldığından, gerçek bir şeyleri kaçırmak için fırsat.

Var olduğunu düşündüğüm bir diğer konu zaman aşımları veya kopmuş bağlantılar. Bu hala geri alınıyor mu? Bu, SET XACT_ABORT ON'un neden kullanılması gerektiğine dair bir anlayış, bu durumlarda işlem geri alınacak.

Geri bildiriminiz için şimdiden teşekkür ederiz!


4
Belirtilen amaçlarına hizmet etmeyen yorumlar silindi veya Topluluk Wiki yanıtına taşındı.
Paul White

Yanıtlar:


61

Sen olamaz değil SQL Server (ve muhtemelen başka uygun RDBMS) işlemlerini kullanırlar. Açık işlem sınırlarının ( begin transaction... commit) yokluğunda, her SQL ifadesi, ifade tamamlandıktan (veya başarısız olduktan) sonra örtülü olarak işlenen (veya geri alınan) yeni bir işlem başlatır.

Kendisini "DBA" olarak sunan kişi tarafından önerilen işlem simülasyonu, işlem işlemenin dört zorunlu özelliğinden üçünü temin edememektedir, çünkü yalnızca "yumuşak" hatalara hitap eder ve "zor" hatalarla başa çıkamaz. ağ bağlantısı kesilir, elektrik kesintileri, disk arızası vb.

  • Atomiklik: başarısız. Sözde işleminizin ortasında bir yerde "zor" bir hata oluşursa, değişiklik atomik olmayacaktır.

  • Tutarlılık: başarısız. Yukarıdakilerden, verilerinizin "sert" bir hatadan sonra tutarsız bir durumda olacağını izler.

  • İzolasyon: başarısız. Eşzamanlı bir sözde işlem , sizin işlem tamamlanmadan sözde işleminiz tarafından değiştirilen verilerin bir kısmını değiştirebilir.

  • Dayanıklılık: başarı. Yaptığınız değişiklikler dayanıklı olacaktır , veritabanı sunucusu bunu sağlayacaktır; meslektaşının yaklaşımının berbat edemediği tek şey bu.

Kilitler, her türlü veya RDBMS'de işlemlerin ACID'sini sağlamak için yaygın olarak kullanılan ve ampirik olarak başarılı bir yöntemdir (bu site bir örnek teşkil etmektedir). Rastgele bir DBA'nın eşzamanlılık sorununa, son olarak ilginç veritabanı sistemleri inşa eden yüzlerce, belki de binlerce bilgisayar bilimcisinden ve mühendisinden daha iyi bir çözüm bulabilmesi pek olası değildir. 60 yıl mı? (Bunun bir "otoriteye itiraz" argümanı olarak yanıltıcı olduğunun farkındayım, ama ne olursa olsun buna bağlı kalacağım.)

Sonuç olarak, eğer yapabilirseniz "DBA" tavsiyesini dikkate almayın, ruhunuz varsa onunla savaşın ve ortaya çıkarlarsa belirli eşzamanlılık problemleriyle geri dönün.


14

CATCH bloğuna asla girilmeyecek kadar ciddi bazı hatalar var. Gönderen dokümantasyon

SQL Server Database Engine görev oturumunu işlemeyi durduran 20 veya daha yüksek şiddeti olan hatalar. 20 veya daha yüksek şiddete sahip bir hata oluşursa ve veritabanı bağlantısı kopmazsa, TRY ... CATCH hatayı işleyecektir.

İstemci kesintisi istekleri veya kopuk istemci bağlantıları gibi dikkatler.

Oturum, KILL deyimini kullanarak sistem yöneticisi tarafından sonlandırıldığında.

...

Bir toplu iş çalışmasını engelleyen sözdizimi hataları gibi hataları derleyin.

Ertelenen ad çözümlemesi nedeniyle oluşan hatalar.

Bunların çoğunu dinamik SQL ile üretmek kolaydır. Gösterdiğiniz gibi geri alma ifadeleri verilerinizi bu tür hatalardan korumaz.


2
Doğru - ve eğer başka bir şey yoksa, kodu yürütürken ölen müşteri "CATCH bloğuna asla girilmeyecek kadar ciddi" bir hataya yol açar. Yazılıma ne kadar güvendiğiniz önemli değil (yalnızca kendi kodunuzla değil, aynı zamanda tüm yazılım yığınlarının HER bölümüyle de), her zaman sizi her an soğukta durduracak bir donanım arızası olasılığı (yine, zincir boyunca potansiyel olarak her yerde) . Bu akılda tutulması, bu tür "geçici çözüm" yol açan kibar düşünceye karşı iyi bir savunmadır.
Eylül’de 13:23

2
Ayrıca, bir kilitlenme kurbanı olabilirsiniz. CATCH bloklarınız çalışıyor fakat veritabanına yazmaya çalışırlarsa atıyorlar.
Joshua,

10

i-tek : Size sürülmektedir geçici çözüm olası (en azından) ihlal "A" yapan ASİT . Örneğin, SP uzaktaki bir istemci tarafından yürütülüyorsa ve bağlantı koparsa, sunucuiki ekleme / silme arasındaki oturumu sonlandırabileceğinden ("SP yürütmesini sona erdirmeden iptal edebilir"), kısmi "taahhüt" / "geri alma" gerçekleşebilir..

Bu, işlemler için uygun bir geçici çözüm olarak mantıklı geliyor mu?

dan-guzman : Hayır,CATCHsorgu zaman aşımı durumunda blok asla çalıştırılmaz, çünkü istemci API toplu işlemi iptal etti. Bir işlem olmadanSET XACT_ABORT ON, geçerli ifadeden başka bir şeyi geri alamazsınız.

tibor-karaszi : 4 işleminiz var, işlem günlüğü dosyasına daha fazla giriş yapın. Her bir işlemin o noktaya kadar günlük kayıtlarının eşzamanlı olarak yazılmasını gerektirdiğini unutmayın; yani, birçok işlemi kullanırken bu açıdan daha kötü performans elde edersiniz.

rbarryyoung : Çok fazla engelleme yaşıyorlarsa , ya veri tasarımlarını düzeltmeleri, tablo erişim düzenlerini rasyonelleştirmeleri ya da daha uygun bir izolasyon seviyesi kullanmaları gerekir. Problemlerinin (ve bunu anlamadaki başarısızlığın) sizin probleminiz olacağını varsayıyorlar. Milyonlarca başka veri tabanından elde edilen kanıtlar bunun olmayacağıdır.

Ayrıca, el ile uygulamaya çalıştıkları, etkili bir şekilde fakir insanların iyimser eşzamanlılıklarıdır. Bunun yerine, yapmaları gereken, zaten SQL Server'da bulunan, dünyadaki en iyi iyimser eşzamanlılıklarını kullanmaktır. Bu, yukarıdaki izolasyon noktasına gider. Büyük olasılıkla onlar şu anda iyimser eşzamanlılık izolasyon seviyelerinin birine kullandığınız ne olursa olsun kötümser eşzamanlılık izolasyon seviyesinden anahtara ihtiyaç SNAPSHOTveya READ_COMMITTED_SNAPSHOT. Bunlar, doğru şekilde yapması dışında, manuel kodları ile aynı şeyi etkili bir şekilde yapacaktır.

ross-presser : Çok uzun süren bir işleminiz varsa - bugün ve gelecek hafta bir şeyler olması gerektiği gibi bir şey takip etmek zorunda kalır ve gelecek haftaki şeyler başarısız olursa o zaman bugün geriye dönük olarak başarısız olmak zorunda kalır - sarkmalara bakmak isteyebilirsiniz . Açıkça söylemek gerekirse, bunun bir servis veri yolu gerektirmesi nedeniyle veritabanının dışında olduğu söylenebilir.


5

Kötü fikir kodu sadece çizgiyi düzeltmek için daha pahalı olacak.

Açık işlem kullanarak engelleme sorunları varsa (geri alma / işleme), sorunların giderilmesi için bazı harika fikirler için DBA’nızı İnternet’e yönlendirin.

Engellemeyi hafifletmeye yardımcı olacak bir yol: https://www.sqlservercentral.com/articles/using-indexes-to-reduce-blocking-in-concurrent-transactions

Dizinler, bir satır / satır kümesi bulmak için bir tabloda / sayfada olması gereken arama sayısını azaltır. Genellikle SELECT * sorguları için yürütme zamanlarını ve haklı olarak azaltma yöntemi olarak görülürler. Çok sayıda GÜNCELLEME ile ilgili tablolar için uygun sayılmazlar. Aslında, INDEXES'in bu gibi durumlarda UPDATE sorgularını tamamlamak için harcanan zamanı arttırdığı için sakıncalı olduğu bulunmuştur.

Ancak bu her zaman böyle değildir. Bir UPDATE ifadesinin yürütülmesine biraz derinlemesine baktığımızda, önce SELECT ifadesinin yürütülmesini de içerdiğini görüyoruz. Bu, sorguların birbirini dışlayan satır kümelerini güncelleştirdiği özel ve sık görülen bir senaryodur. Buradaki ENDEKSLER, popüler inanca aykırı olarak veritabanı motorunun performansında önemli bir artışa yol açabilir.


4

Sahte işlem stratejisi tehlikelidir çünkü işlemlerin özellikle önlediği eşzamanlılık sorunlarına izin verir. İkinci örnekte verilerin herhangi birinin ifadeler arasında değişebileceğini düşünün.

Sahte işlem silinmesi, çalıştırılması veya başarılı olması için GARANTİLİ DEĞİLDİR. Sahte işlem sırasında veritabanı sunucusu kapanırsa, efektlerin bazıları değil ancak tümü korunacaktır. Ayrıca, işlemlerin geri alınmasının söz konusu olduğu şekilde başarılı olmaları garanti edilmez.

Bu strateji eklerle birlikte çalışabilir, ancak kesinlikle güncelleme veya silme işlemleriyle çalışmaz (zaman çizelgesi SQL deyimleri olmadan).

Sıkı işlem eşzamanlılığı engellemeye neden oluyorsa, çok sayıda çözüm vardır, hatta koruma seviyesini düşürenler bile ... bunlar sorunu çözmenin doğru yoludur.

DBA'nız, veritabanının yalnızca bir kullanıcısı varsa tamam işe yarayacak bir çözüm sunuyor, ancak kesinlikle her türlü ciddi kullanım için uygun değil.


4

Bu bir programlama konusu değil, kişilerarası / iletişimsizlik sorunudur. Büyük olasılıkla "DBA" işlemleriniz değil kilitleriniz için endişeleniyor.

Diğer cevaplar zaten neden işlemleri kullanmak zorunda olduğunuzu açıklıyor ... Yani RDBMS'nin yaptığı şey bu; doğru kullanılan işlemler olmadan veri bütünlüğü yok, bu yüzden asıl problemin nasıl çözüleceğine odaklanacağım. "DBA" işlemlere karşı bir alerji geliştirdi ve fikrini değiştirmeye ikna etti.

Bu adamın "kötü kodun korkunç performansa neden olduğu belirli bir senaryo" ile "tüm işlemler kötü" olduğunu düşünüyorum. Yetkili bir DBA'nın bu hatayı yapmasını beklemiyorum, bu gerçekten garip. Belki de korkunç bir kodla gerçekten kötü bir deneyim yaşadı?

Bunun gibi bir senaryo düşünün:

BEGIN
UPDATE or DELETE some row, which takes locks it
...do something that takes a while
...perform other queries
COMMIT

Bu işlem kullanım tarzı bir kilit (ya da birkaç kilit) tutar, yani aynı satıra vuran diğer işlemlerin beklemesi gerekir. Kilitler uzun bir süre boyunca tutulursa ve özellikle birçok işlem aynı satırları kilitlemek istiyorsa, bu gerçekten performansa zarar verebilir.

Yapabilecekleriniz, neden işlemleri merak etmemek, neden sorgular soruna yol açmamak gibi nedenlerin meraklı bir şekilde yanlış olduğu fikrine sahip olduğunu sormak. Daha sonra, onu, benzer kötü senaryolardan kaçınacağınıza, kilit kullanımınızı izleyeceğinize kesinlikle ikna etmeye çalışın ve performans, ona güvence vb.

Sana söylediği şey "tornavidaya dokunma!" bu yüzden sorunuzda yayınladığınız kod temel olarak bir vida sürmek için bir çekiç kullanıyor. Çok daha iyi bir seçenek onu tornavida kullanmayı bildiğinize ikna etmek ...

Birkaç örnek düşünebilirim ... peki, onlar MySQL'deydi ama bu da işe yaramalı.

Tam metin dizininin güncellenmesinin zaman aldığı bir forum vardı. Bir kullanıcı bir gönderi gönderdiğinde, işlem gönderi sayısını ve son gönderi tarihini artırmak için konu tablosunu günceller (böylece konu satırını kilitler), ardından gönderiyi ekler ve işlem tam metin dizini güncelleştirmesi tamamlanıncaya kadar kilidi tutar ve KOMİTE yapıldı.

Bu, çok az RAM içeren bir paslı oyunda çalıştığından, bahsedilen tam metin dizinini güncellemek, kutudaki tek yavaş dönen sürücüde birkaç saniye yoğun rastgele IO ile sonuçlandı.

Sorun, konuyu tıklayan kişilerin, konunun görünüm sayısını artırması için bir sorgunun ortaya çıkmasıydı; bu da konu satırında bir kilitlenmeyi gerektiriyordu. Böylece, tam metin dizini güncellenirken hiç kimse konuyu göremezdi. Demek istediğim, satır okunabilir, ancak güncellenmesi kilitlenir.

Daha da kötüsü, deftere nakil, ana forumlar tablosundaki gönderi sayısını günceller ve tam metin dizini güncellenirken kilidi tutardı ... bu da tüm forumun birkaç saniyeliğine donduğunu ve tonlarca isteğin web sunucusu kuyruğunda birikmesine neden oldu. .

Çözüm, kilitleri doğru sırayla almaktı: BEGIN, yazıyı yerleştirin ve tam metin dizinini herhangi bir kilit kullanmadan güncelleyin, sonra konu / forum satırlarını hızlı bir şekilde güncelleyin ve yazı sayısı ve son yazı tarihi ile COMMIT. Bu sorunu tamamen çözdü. Sadece birkaç sorgu etrafında ilerliyordu, gerçekten basit.

Bu durumda, işlemler sorun değildi ... Uzun bir operasyondan önce gereksiz bir kilit elde ediyordu. Bir işlemde bir kilidi tutarken kaçınılması gereken diğer şeyler: kullanıcı girişi için bekliyor, yavaş dönen sürücülerden, ağ G / Ç'den, vb.

Tabii ki, bazen, bir seçeneğiniz yoktur ve hantal kilitleri tutarken uzun bir işlem yapmanız gerekir. Bu konuda hileler vardır (verilerin bir kopyasında vb. Çalışır), ancak performans darboğazı kasıtlı olarak edinilmemiş bir kilitten gelir ve çoğunlukla sorguları yeniden düzenlemek sorunu çözer. Daha da iyisi, sorguları yazarken alınan kilitlerin farkında olmak ...

Diğer cevapları tekrarlamayacağım ama gerçekten ... işlemleri kullan. Sorununuz "DBA" nı ikna etmek, bir veritabanının en önemli özelliği etrafında çalışmamak ...


3

TLDR: Uygun izolasyon seviyesini kullanın .

Doğru bir şekilde farketmediğiniz gibi işlem yapmadan ve "elle" kurtarma ile çok karmaşık olabilir. Yüksek karmaşıklık normalde onu uygulamak için çok daha fazla zaman ve hataları düzeltmek için çok daha fazla zaman demektir (çünkü karmaşıklık uygulamada daha fazla hataya neden olur). Bu tür bir yaklaşımın müşterinize çok daha fazla mal olabileceği anlamına gelir.

"Dba" meslektaşınızın asıl endişesi performanstır. Bunu iyileştirmenin yollarından biri uygun izolasyon seviyesini kullanmaktır. Kullanıcıya bir tür genel bakış verisi sağlayan bir prosedür olduğunu varsayalım. Bu prosedür mutlaka SERİLEŞTİRİLEN izolasyon seviyesini kullanmak zorunda değildir. Birçok durumda READ UNCOMMITTED oldukça yeterli olabilir. Bu, böyle bir prosedürün bazı verileri yaratan veya değiştiren işleminiz tarafından engellenmeyeceği anlamına gelir .

Veritabanınızdaki mevcut tüm fonksiyonları / prosedürleri gözden geçirmenizi, her biri için makul yalıtım seviyesini değerlendirmenizi, performans avantajlarını müşterinize açıklamanızı öneririm. Ardından bu işlevleri / prosedürleri uygun şekilde ayarlayın.


2

Ayrıca Bellek İçi OLTP tablolarını kullanmaya da karar verebilirsiniz. Tabii ki hala işlemleri kullanıyorlar, ancak engelleme söz konusu değil.
Engellemek yerine tüm işlemler başarılı olacak, ancak işlem aşamasında motor işlem çatışmalarını kontrol edecek ve taahhütlerden biri başarısız olabilir. Microsoft "İyimser kilitleme" terimini kullanır.
Ölçeklendirme sorunu, aynı satırı güncellemeye çalışan iki eşzamanlı işlem gibi iki yazma işlemi arasındaki çelişkiden kaynaklanıyorsa, Bellek İçi OLTP bir işlemin başarılı olmasına ve diğer işlemi başarısız olmasına izin verir. Başarısız olan işlem, işlemi yeniden denemek için açıkça veya dolaylı olarak yeniden gönderilmelidir.
Daha fazla: Bellekte OLTP


-5

İşlemleri sınırlı miktarda kullanmanın bir yolu vardır ve bu, veri modelinizi daha fazla nesne yönelimli olacak şekilde değiştirmektir. Örneğin, bir kişi hakkında birkaç tablodaki demografik verileri depolamak ve bunları birbiriyle ilişkilendirmek ve işlem yapmak yerine, o kişi hakkında bildiğiniz her şeyi tek bir alanda saklayan tek bir JSON belgeniz olabilir. Tabi ki, bu alanın genişlediğine dikkat çekmek, en iyi DBA'lar değil geliştiriciler tarafından yapılan başka bir tasarım zorluğudur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.