Çalıştırmadan önce bir SQL Update deyimi nasıl test edilir?


95

Bazı durumlarda, üretimde bir UPDATE deyimi çalıştırmak günü kurtarabilir. Bununla birlikte, borked bir güncelleme, ilk sorundan daha kötü olabilir.

Bir test veritabanı kullanmanın yanı sıra, bir güncelleme ifadesinin çalıştırmadan önce ne yapacağını söyleyen seçenekler nelerdir?

Yanıtlar:


53

Imad'ın söylediği gibi (zaten zorunlu olması gereken) bir işlemi kullanmanın yanı sıra, UPDATE ile aynı WHERE cümlesini kullanarak bir seçim çalıştırarak hangi satırların etkilendiğini de kontrol edebilirsiniz.

Yani UPDATE

UPDATE foo
  SET bar = 42
WHERE col1 = 1
  AND col2 = 'foobar';

Aşağıdakiler size hangi satırların güncelleneceğini gösterecektir:

SELECT *
FROM foo
WHERE col1 = 1
  AND col2 = 'foobar';

1
O zaman verileri kontrol etmek için işlemleri kullanmak daha iyidir. Sonucu kontrol etmek istediğini varsayarsak, ifadesinin bir 'SET çubuğu = 42'den daha karmaşık olduğu sonucuna vardım, bu yüzden seansı sırasında ortaya çıkan veri kümesini test etmek için birkaç sorgu yapabilecek ...
Imad Moqaddem

3
@ImadMoqaddem: Kabul ediyorum ve bu yüzden "
Imad'ın

Ve FOREIGN KEY UPDATE CASCADESQL'iniz başarısız olursa
Green

@Green: "Başarısız" derken ne demek istiyorsun?
a_horse_with_no_name

78

İşlemler ne olacak? ROLLBACK-Özelliğine sahiptirler.

@see https://dev.mysql.com/doc/refman/5.0/en/commit.html

Örneğin:

START TRANSACTION;
SELECT * FROM nicetable WHERE somthing=1;
UPDATE nicetable SET nicefield='VALUE' WHERE somthing=1;
SELECT * FROM nicetable WHERE somthing=1; #check

COMMIT;
# or if you want to reset changes 
ROLLBACK;

SELECT * FROM nicetable WHERE somthing=1; #should be the old value

Aşağıdaki @rickozoe tarafından sorulan soruya cevap:

Genelde bu satırlar bir kez çalıştırılmayacaktır. PHP fe'de böyle bir şey yazarsınız (belki biraz daha temiz, ancak hızlı yanıt vermek istersiniz ;-)):

$MysqlConnection->query('START TRANSACTION;');
$erg = $MysqlConnection->query('UPDATE MyGuests SET lastname='Doe' WHERE id=2;');
if($erg)
    $MysqlConnection->query('COMMIT;');
else
    $MysqlConnection->query('ROLLBACK;');

Başka bir yol da MySQL Değişkenlerini kullanmaktır (bkz. Https://dev.mysql.com/doc/refman/5.7/en/user-variables.htm l ve https://stackoverflow.com/a/18499823/1416909 ):

# do some stuff that should be conditionally rollbacked later on

SET @v1 := UPDATE MyGuests SET lastname='Doe' WHERE id=2;
IF(v1 < 1) THEN
    ROLLBACK;
ELSE
    COMMIT;
END IF;

Ama en sevdiğiniz programlama dilinde mevcut olan dil sarmalayıcıları kullanmanızı öneririm.


1
Bunun iç içe geçmiş işlemlerle beklenmedik sonuçları olacaktır.
çörekler

Lütfen bir örnek verebilir misiniz?
Marcel Lange

@JCM ve diğerleri, güncelleme ifadesinin 3. satırda başarılı olup olmadığını nasıl bilebilirsiniz, böylece taahhüt ve geri alma yapabilirsiniz?
ricko zoe

57

Otomatik teslim KAPALI ...

MySQL

set autocommit=0;

Mevcut oturum için otomatikleştirmeyi kapatır.

İfadenizi yürütür, neyin değiştiğini görürsünüz ve sonra yanlışsa geri alınır veya beklediğiniz şeyse taahhütte bulunur!

DÜZENLEME: Seçme sorgusu çalıştırmak yerine işlemleri kullanmanın yararı, elde edilen seti daha kolay kontrol edebilmenizdir.


4
@dystroy: Her mantıklı DBMS işlemleri destekler.
a_horse_with_no_name

7
İşlemi hızlı bir şekilde gerçekleştirmeyi veya geri almayı unutmayın, aksi takdirde diğer işlemleri engelleme riskiyle karşı karşıya kalırsınız - ve en kötü durumda uygulamanızı durma noktasına getirirsiniz. Sorguyu yürütmek, sonra öğle yemeği yemek ve ardından sonuçları görmek için geri dönmek iyi bir fikir değil! :-)
Gary McGill

@GaryMcGill: Bekleyen işlem (en azından modern DBMS'de) yalnızca diğer yazma işlemlerini engelleyecektir .
a_horse_with_no_name

5
@dystroy: Ne yazık ki, MyISAM her yerde kullanılıyor ve ben DBA değilim.
static_rtti

1
Sql ifadesi eklendi :)
Imad Moqaddem

11

Bunun diğer yanıtların tekrarı olduğunu biliyorum, ancak güncellemeyi test etmek için fazladan bir adım atmak için biraz duygusal destek var: D

Güncellemeyi test etmek için, hash # arkadaşınızdır.

Aşağıdaki gibi bir güncelleme bildiriminiz varsa:

UPDATE 
wp_history
SET history_by="admin"
WHERE
history_ip LIKE '123%'

GÜNCELLEME ve test için AYARLA hashing uygularsınız, ardından bunları tekrar hash hale getirirsiniz:

SELECT * FROM
#UPDATE
wp_history
#SET history_by="admin"
WHERE
history_ip LIKE '123%'

Basit ifadeler için işe yarar.

Pratik olarak zorunlu ek bir çözüm, bir üretim tablosunda güncelleme kullanıldığında bir kopya (yedek kopya) almaktır. Phpmyadmin> işlemler> kopyala: table_yearmonthday. <= 100M tablolar için sadece birkaç saniye sürer.


5

Doğrudan bir cevap değil, ancak ilk önce cümleyi yazarakWHERE önlenebilecek birçok borked prod verisi durumu gördüm ! Bazen bir WHERE 1 = 0çalışma ifadesini güvenli bir şekilde bir araya getirmeye de yardımcı olabilir. Ve etkilenen satırları tahmin edecek tahmini bir yürütme planına bakmak faydalı olabilir. Bunun ötesinde, başkalarının söylediği gibi geri aldığınız bir işlemde.


2
@SystemParadox - WHERE 1 = 0farklı bir DBMS ile çalışan biri bununla karşılaşırsa hiçbir şey daha taşınabilir değildir. Örneğin, SQL Server kabul etmeyecektir WHERE FALSE.
David M

2

Test etmek istediğiniz bu durumlarda, yalnızca geçerli sütun değerlerine ve yakında güncellenecek sütun değerlerine odaklanmak iyi bir fikirdir .

Lütfen WHMCS fiyatlarını güncellemek için yazdığım aşağıdaki koda bir göz atın:

# UPDATE tblinvoiceitems AS ii

SELECT                        ###  JUST
    ii.amount AS old_value,   ###  FOR
    h.amount AS new_value     ###  TESTING
FROM tblinvoiceitems AS ii    ###  PURPOSES.

JOIN tblhosting AS h ON ii.relid = h.id
JOIN tblinvoices AS i ON ii.invoiceid = i.id

WHERE ii.amount <> h.amount   ### Show only updatable rows

# SET ii.amount = h.amount

Bu şekilde, halihazırda mevcut değerleri yeni değerlerle açıkça karşılaştırırız.


1

whereGüncelleme sorgusunda uyguladığınız tüm koşullarla aynı tabloda seçme sorgusunu çalıştırın .


0

Bir yapmak SELECTo,

eğer sahipsen gibi

UPDATE users SET id=0 WHERE name='jan'

dönüştürmek

SELECT * FROM users WHERE name='jan'


0

Bir seçenek daha MySQL'den sorgu planı istemektir. Bu size iki şey anlatır:

  • Sorguda herhangi bir sözdizimi hatası olup olmadığı, öyleyse sorgu planı komutunun kendisi başarısız olur
  • MySQL sorguyu nasıl yürütmeyi planlıyor, örneğin hangi dizinleri kullanacak?

MySQL'de ve çoğu SQL veritabanında sorgu planı komutu şu şekildedir describe, yani şunları yaparsınız:

describe update ...;
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.