Bagaimana cara menguji pernyataan Pembaruan SQL sebelum menjalankannya?

95

Dalam beberapa kasus, menjalankan pernyataan UPDATE dalam produksi dapat menghemat waktu. Namun pembaruan yang rusak bisa lebih buruk dari masalah awal.

Singkatnya menggunakan database pengujian, apa saja opsi untuk mengetahui apa yang akan dilakukan pernyataan pembaruan sebelum menjalankannya?

static_rtti
sumber

Jawaban:

53

Selain menggunakan transaksi seperti yang dikatakan Imad (yang seharusnya wajib) Anda juga dapat melakukan pemeriksaan kesehatan baris mana yang terpengaruh dengan menjalankan pemilihan menggunakan klausa WHERE yang sama dengan UPDATE.

Jadi jika Anda UPDATE

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

Berikut ini akan menunjukkan kepada Anda baris mana yang akan diperbarui:

SELECT *
FROM foo
WHERE col1 = 1
  AND col2 = 'foobar';
seekor kuda tanpa nama
sumber
1
Menggunakan transaksi lebih baik untuk memeriksa data. Dengan asumsi dia ingin memeriksa hasilnya, saya menyimpulkan pernyataannya lebih kompleks daripada 'SET bar = 42', jadi dalam sesinya dia akan dapat membuat beberapa kueri untuk menguji kumpulan data yang dihasilkan ...
Imad Moqaddem
3
@ImadMoqaddem: Saya setuju dan itulah mengapa saya menulis " Selain menggunakan transaksi seperti yang dikatakan Imad "
a_horse_with_no_name
Dan jika FOREIGN KEY UPDATE CASCADEsql Anda gagal
Hijau
@Green: apa yang Anda maksud dengan "gagal"?
a_horse_with_no_name
76

Bagaimana dengan Transaksi? Mereka memiliki Fitur ROLLBACK.

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

Sebagai contoh:

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

Jawab pertanyaan dari @rickozoe di bawah ini:

Secara umum baris ini tidak akan dijalankan sekali. Di PHP fe Anda akan menulis sesuatu seperti itu (mungkin sedikit lebih bersih, tetapi ingin menjawab dengan cepat ;-)):

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

Cara lain adalah dengan menggunakan Variabel MySQL (lihat https://dev.mysql.com/doc/refman/5.7/en/user-variables.htm l dan 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;

Tetapi saya akan menyarankan untuk menggunakan pembungkus bahasa yang tersedia dalam bahasa pemrograman favorit Anda.

Marcel Lange
sumber
1
Ini akan memberikan hasil yang tidak diharapkan dengan transaksi bersarang.
scone
Bisakah Anda memberi contoh?
Marcel Lange
@JCM dan lainnya, bagaimana Anda dapat mengetahui jika berhasil pernyataan pembaruan berhasil di baris 3 sehingga Anda dapat berkomitmen dan rollback?
ricko zoe
57

Komit Otomatis NONAKTIF ...

MySQL

set autocommit=0;

Ini menyetel autommit off untuk sesi saat ini.

Anda menjalankan pernyataan Anda, melihat apa yang telah berubah, dan kemudian mengembalikan jika itu salah atau berkomitmen jika itu yang Anda harapkan!

EDIT: Manfaat menggunakan transaksi daripada menjalankan kueri pemilihan adalah Anda dapat memeriksa set yang dihasilkan dengan lebih mudah.

Imad Moqaddem
sumber
4
@dystroy: setiap DBMS yang masuk akal mendukung transaksi.
a_horse_with_no_name
7
Ingatlah untuk melakukan atau membatalkan transaksi dengan cepat, atau Anda berisiko memblokir transaksi lain - dan dalam kasus terburuk membuat aplikasi Anda terhenti. Bukan ide yang baik untuk mengeksekusi kueri, lalu makan siang, lalu kembali untuk melihat hasilnya! :-)
Gary McGill
@GaryMcGill: transaksi yang tertunda (setidaknya dalam DBMS modern) hanya akan memblokir transaksi tulis lainnya .
a_horse_with_no_name
5
@dystroy: Sayangnya, MyISAM digunakan di mana-mana, dan saya bukan DBA.
static_rtti
1
Pernyataan Sql ditambahkan :)
Imad Moqaddem
11

Saya tahu ini adalah pengulangan jawaban lain, tetapi memiliki dukungan emosional untuk mengambil langkah ekstra untuk menguji pembaruan: D

Untuk pengujian pembaruan, hash # adalah teman Anda.

Jika Anda memiliki pernyataan pembaruan seperti:

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

Anda melakukan hash UPDATE dan SET out untuk pengujian, lalu hash mereka kembali:

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

Ini bekerja untuk pernyataan sederhana.

Solusi tambahan yang praktis wajib adalah, untuk mendapatkan salinan (duplikat cadangan), setiap kali menggunakan pembaruan pada tabel produksi. Phpmyadmin> operasi> salin: table_yearmonthday. Hanya membutuhkan beberapa detik untuk tabel <= 100M.

Johan
sumber
5

Bukan jawaban langsung, tetapi saya telah melihat banyak situasi data prod yang rusak yang dapat dihindari dengan mengetikkan WHEREklausa terlebih dahulu ! Kadang-kadang WHERE 1 = 0dapat membantu menyusun pernyataan kerja dengan aman juga. Dan melihat rencana pelaksanaan yang diperkirakan, yang akan memperkirakan baris yang terpengaruh, dapat berguna. Di luar itu, dalam transaksi yang Anda batalkan seperti yang dikatakan orang lain.

David M
sumber
2
@SystemParadox - tidak ada, meskipun WHERE 1 = 0lebih portabel jika ada yang menemukan ini yang bekerja dengan DBMS yang berbeda. Misalnya, SQL Server tidak akan menerima WHERE FALSE.
David M
2

Dalam kasus ini yang ingin Anda uji, sebaiknya fokus hanya pada nilai kolom saat ini dan segera diperbarui. .

Silakan lihat kode berikut yang saya tulis untuk memperbarui harga WHMCS:

# 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

Dengan cara ini kami dengan jelas membandingkan nilai yang sudah ada dengan nilai baru.

Mohammad Naji
sumber
1

Jalankan kueri pemilihan pada tabel yang sama dengan semua wherekondisi yang Anda terapkan dalam kueri pembaruan.

manurajhada
sumber
0

buat SELECTitu,

seperti jika Anda punya

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

ubah menjadi

SELECT * FROM users WHERE name='jan'

EaterOfCode
sumber
0

Satu opsi lagi adalah meminta MySQL untuk rencana kueri. Ini memberi tahu Anda dua hal:

  • Apakah ada kesalahan sintaks dalam kueri, jika demikian perintah rencana kueri itu sendiri akan gagal
  • Bagaimana MySQL berencana untuk mengeksekusi kueri, misalnya indeks apa yang akan digunakannya

Di MySQL dan sebagian besar database SQL, perintah query plan adalah describe, jadi Anda akan melakukan:

describe update ...;
Yawar
sumber