จะทดสอบคำสั่ง SQL Update ก่อนรันได้อย่างไร


95

ในบางกรณีการเรียกใช้คำสั่ง UPDATE ในการใช้งานจริงสามารถช่วยประหยัดวันได้ อย่างไรก็ตามการอัปเดต borked อาจแย่กว่าปัญหาเริ่มต้น

ขาดการใช้ฐานข้อมูลทดสอบมีตัวเลือกอะไรบ้างที่จะบอกว่าคำสั่งอัพเดตจะทำอะไรก่อนเรียกใช้

คำตอบ:


53

นอกเหนือจากการใช้ธุรกรรมตามที่ Imad ได้กล่าวไว้แล้ว (ซึ่งควรจะต้องมีผลต่อไป) คุณยังสามารถตรวจสอบว่าแถวใดได้รับผลกระทบจากการเรียกใช้การเลือกโดยใช้ WHERE clause เดียวกับ UPDATE

ดังนั้นหากคุณอัปเดตเป็น

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

ต่อไปนี้จะแสดงให้คุณเห็นว่าแถวใดจะได้รับการอัปเดต:

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

1
การใช้ธุรกรรมจะดีกว่าเพื่อตรวจสอบข้อมูล สมมติว่าเขาต้องการตรวจสอบผลลัพธ์ฉันสรุปว่าคำสั่งของเขาซับซ้อนกว่า 'SET bar = 42' ดังนั้นภายในเซสชันของเขาเขาจะสามารถทำการสอบถามหลายครั้งเพื่อทดสอบชุดข้อมูลที่เป็นผลลัพธ์ ...
Imad Moqaddem

3
@ImadMoqaddem: ฉันเห็นด้วยและนั่นคือเหตุผลที่ฉันเขียนว่า " นอกเหนือจากการใช้ธุรกรรมตามที่ Imad พูด "
a_horse_with_no_name

และถ้าคุณมีFOREIGN KEY UPDATE CASCADEsql ของคุณล้มเหลว
Green

@ กรีน: คำว่า "ล้มเหลว" หมายความว่าอย่างไร?
a_horse_with_no_name

77

แล้วธุรกรรมล่ะ? พวกเขามีคุณสมบัติ ROLLBACK

@ ดูhttps://dev.mysql.com/doc/refman/5.0/th/commit.html

ตัวอย่างเช่น:

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

ตอบคำถามจาก @rickozoe ด้านล่าง:

โดยทั่วไปบรรทัดเหล่านี้จะไม่ถูกดำเนินการเพียงครั้งเดียว ใน PHP fe คุณจะเขียนอะไรแบบนั้น (อาจจะดูสะอาดกว่าเล็กน้อย แต่ต้องการคำตอบอย่างรวดเร็ว ;-)):

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

อีกวิธีหนึ่งคือการใช้ MySQL Variables (ดูhttps://dev.mysql.com/doc/refman/5.7/en/user-variables.htm l และ 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;

แต่ฉันขอแนะนำให้ใช้ตัวตัดภาษาที่มีอยู่ในภาษาโปรแกรมที่คุณชื่นชอบ


1
สิ่งนี้จะได้ผลลัพธ์ที่ไม่คาดคิดกับธุรกรรมที่ซ้อนกัน
scones

ช่วยยกตัวอย่างได้ไหม
Marcel Lange

@JCM และอื่น ๆ คุณจะรู้ได้อย่างไรว่าคำสั่งอัพเดตประสบความสำเร็จในบรรทัดที่ 3 คุณจึงสามารถคอมมิตและย้อนกลับได้หรือไม่?
ricko zoe

57

ปิด Autocommit ...

MySQL

set autocommit=0;

มันตั้งค่าการคอมมิตอัตโนมัติสำหรับเซสชันปัจจุบัน

คุณดำเนินการตามคำสั่งของคุณดูว่ามีการเปลี่ยนแปลงอะไรบ้างแล้วย้อนกลับหากผิดหรือกระทำหากเป็นไปตามที่คุณคาดไว้!

แก้ไข: ประโยชน์ของการใช้ธุรกรรมแทนการเรียกใช้แบบสอบถามแบบเลือกคือคุณสามารถตรวจสอบชุดผลลัพธ์ได้ง่ายขึ้น


4
@dystroy: ทุก DBMS ที่สมเหตุสมผลรองรับการทำธุรกรรม
a_horse_with_no_name

7
อย่าลืมทำธุรกรรมหรือย้อนกลับธุรกรรมอย่างรวดเร็วมิฉะนั้นคุณอาจเสี่ยงต่อการปิดกั้นธุรกรรมอื่น ๆ และในกรณีที่เลวร้ายที่สุดจะทำให้แอปพลิเคชันของคุณหยุดชะงัก ไม่ใช่ความคิดที่ดีที่จะดำเนินการค้นหาจากนั้นรับประทานอาหารกลางวันจากนั้นกลับมาดูผลลัพธ์! :-)
Gary McGill

@GaryMcGill: ธุรกรรมที่รอดำเนินการ (อย่างน้อยใน DBMS สมัยใหม่) จะบล็อกธุรกรรมการเขียนอื่น ๆเท่านั้น
a_horse_with_no_name

5
@dystroy: น่าเสียดายที่ MyISAM ถูกใช้ทุกที่และฉันไม่ใช่ DBA
static_rtti

1
เพิ่มคำสั่ง Sql :)
Imad Moqaddem

11

ฉันรู้ว่านี่เป็นการทำซ้ำคำตอบอื่น ๆ แต่ก็มีการสนับสนุนทางอารมณ์บางอย่างที่จะก้าวไปอีกขั้นสำหรับการทดสอบอัปเดต: D

สำหรับการทดสอบการอัปเดตแฮช # คือเพื่อนของคุณ

หากคุณมีคำสั่งอัพเดตเช่น:

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

คุณแฮชอัปเดตและตั้งค่าสำหรับการทดสอบจากนั้นแฮชกลับใน:

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

มันใช้ได้กับงบง่ายๆ

วิธีแก้ไขเพิ่มเติมที่จำเป็นในทางปฏิบัติคือการรับสำเนา (สำรองข้อมูลซ้ำ) เมื่อใดก็ตามที่ใช้การอัปเดตบนตารางการผลิต phpmyadmin> operation> copy: table_yearmonthday ใช้เวลาเพียงไม่กี่วินาทีสำหรับตาราง <= 100M


5

ไม่ใช่คำตอบโดยตรง แต่ฉันเคยเห็นสถานการณ์ข้อมูล prod borked มากมายที่สามารถหลีกเลี่ยงได้โดยการพิมพ์WHEREประโยคก่อน ! บางครั้งWHERE 1 = 0สามารถช่วยในการวางคำแถลงการทำงานร่วมกันอย่างปลอดภัยได้เช่นกัน และการดูแผนการดำเนินการโดยประมาณซึ่งจะประมาณแถวที่ได้รับผลกระทบจะเป็นประโยชน์ นอกเหนือจากนั้นในการทำธุรกรรมที่คุณย้อนกลับไปตามที่คนอื่นบอก


2
@SystemParadox - ไม่มีอะไรแม้ว่าWHERE 1 = 0จะพกพาได้มากกว่าหากใครเจอสิ่งนี้ซึ่งทำงานกับ DBMS อื่น ยกตัวอย่างเช่น SQL Server WHERE FALSEจะไม่ยอมรับ
David M

2

ในกรณีเหล่านี้ที่คุณต้องการที่จะทดสอบมันเป็นความคิดที่ดีที่จะมุ่งเน้นเฉพาะในปัจจุบันค่าของคอลัมน์และในเร็ว ๆ นี้เพื่อจะปรับปรุงค่าของคอลัมน์

โปรดดูรหัสต่อไปนี้ที่ฉันเขียนเพื่ออัปเดตราคา 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

วิธีนี้ทำให้เราเปรียบเทียบค่าที่มีอยู่แล้วเทียบกับค่าใหม่ได้อย่างชัดเจน


1

เรียกใช้คิวรีแบบเลือกบนตารางเดียวกันโดยมีwhereเงื่อนไขทั้งหมดที่คุณใช้ในคิวรีอัพเดต


0

สร้างSELECTมันขึ้นมา

เช่นถ้าคุณมี

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

แปลงเป็นไฟล์

SELECT * FROM users WHERE name='jan'


0

อีกทางเลือกหนึ่งคือขอ MySQL สำหรับแผนการสืบค้น สิ่งนี้บอกคุณได้สองอย่าง:

  • ไม่ว่าจะมีข้อผิดพลาดทางไวยากรณ์ในแบบสอบถามหรือไม่หากเป็นเช่นนั้นคำสั่งแผนแบบสอบถามเองก็จะล้มเหลว
  • MySQL วางแผนที่จะดำเนินการสืบค้นอย่างไรเช่นจะใช้ดัชนีอะไร

ใน MySQL และฐานข้อมูล SQL ส่วนใหญ่คำสั่งแผนแบบสอบถามคือdescribeดังนั้นคุณต้องทำ:

describe update ...;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.