Berbagi teknologi

Parameter MySQL sql_safe_updates

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

sql_safe_updates adalah variabel sistem di MySQL yang mengontrol apakah server MySQL mengizinkan operasi pembaruan atau penghapusan pada pernyataan UPDATE atau DELETE yang tidak menggunakan klausa KEY atau LIMIT. Ketika variabel ini diatur ke ON, MySQL akan menolak pernyataan UPDATE atau DELETE yang dapat mempengaruhi sejumlah besar baris dalam tabel, kecuali pernyataan ini secara eksplisit menggunakan KEY (seperti kunci utama atau indeks unik) dalam klausa WHERE atau klausa WHERE. Klausa LIMIT untuk Membatasi jumlah baris yang terpengaruh.

Tujuannya adalah untuk mencegah hilangnya atau modifikasi data dalam jumlah besar secara tidak disengaja karena pernyataan SQL yang ditulis secara ceroboh atau salah.

Cara mengatur sql_safe_updates

Anda dapat mengatur sql_safe_updates dengan beberapa cara:

Tingkat global:

Anda dapat mengatur variabel ini secara permanen dengan memodifikasi file konfigurasi MySQL (seperti my.cnf atau my.ini, bergantung pada sistem operasi dan versi MySQL Anda). Namun, perlu diingat bahwa pengaturan sql_safe_updates secara langsung di file konfigurasi mungkin tidak didukung oleh semua versi MySQL, atau mungkin perlu dikonfigurasi secara berbeda (misalnya melalui plug-in atau variabel sistem lainnya).
Pendekatan yang lebih umum adalah mengaturnya saat runtime menggunakan pernyataan SET GLOBAL MySQL, tetapi ini hanya mempengaruhi koneksi baru. Misalnya:

SET GLOBAL sql_safe_updates = 1;
  • 1

Namun, harap diperhatikan bahwa menyetel variabel global secara langsung mungkin memerlukan hak administrator, dan perubahan ini tidak akan memengaruhi sesi yang ada.

Tingkat sesi:

Anda dapat mengatur sql_safe_updates dengan menjalankan pernyataan SQL berikut di sesi MySQL Anda:

SET SESSION sql_safe_updates = 1;

或者登录时加上--safe-updates 

mysql -uroot -p --safe-updates 
  • 1
  • 2
  • 3
  • 4
  • 5

Hal ini memengaruhi tindakan selanjutnya di sesi saat ini, namun tidak memengaruhi sesi lain atau pengaturan global.

Tindakan pencegahan

  • Dengan sql_safe_updates diaktifkan, jika Anda mencoba menjalankan pernyataan UPDATE atau DELETE tanpa KEY atau LIMIT, MySQL akan menolak operasi tersebut dan mengembalikan kesalahan.
(root@localhost)[superdb]> show index from dept;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| dept  |          0 | PRIMARY  |            1 | deptno      | A         |           4 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
1 row in set (0.13 sec)

(root@localhost)[superdb]> update dept set loc='sz';
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column. 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • Tidak semua penerapan MySQL mengaktifkan sql_safe_updates secara default. Biasanya dikonfigurasi oleh administrator database atau pengembang berdasarkan persyaratan keamanan tertentu.

  • Dalam beberapa kasus, Anda mungkin perlu menonaktifkan sementara sql_safe_updates untuk melakukan operasi pembaruan atau penghapusan massal tertentu. Dalam hal ini, Anda dapat menyetel sql_safe_updates = 0 pada tingkat sesi, namun hati-hati untuk memastikan bahwa pernyataan SQL Anda aman dan tidak secara tidak sengaja memengaruhi data dalam jumlah besar.

Singkatnya, sql_safe_updates adalah fitur keamanan berguna yang dapat membantu mencegah kehilangan data karena kecerobohan atau kesalahan. Namun, hal ini juga mengharuskan pengembang dan administrator database untuk lebih memperhatikan pernyataan SQL mereka untuk memastikan keamanan dan keakuratannya.

penjelasan resmi

Jika ditetapkan ke 1, MySQL membatalkan pernyataan UPDATE atau DELETE yang tidak menggunakan kunci dalam klausa WHERE atau klausa LIMIT. (Secara khusus, pernyataan UPDATE harus memiliki klausa WHERE yang menggunakan kunci atau klausa LIMIT, atau keduanya. Pernyataan DELETE harus memiliki keduanya.) Hal ini memungkinkan untuk menangkap pernyataan UPDATE atau DELETE yang kuncinya tidak digunakan dengan benar dan yang mungkin akan mengubah atau menghapus sejumlah besar baris. Nilai default adalah 0.

Ketika sql_safe_updates diatur ke 1.

  • Pernyataan pembaruan harus memenuhi salah satu kondisi berikut agar berhasil dijalankan:
    • Pernyataan update menggunakan Where, dan harus ada kolom indeks pada kondisi Where;
    • Pernyataan pembaruan menggunakan limit;
    • Pernyataan update menggunakan di mana dan membatasi pada saat yang sama, kondisi di mana tidak perlu memiliki kolom indeks;
(root@localhost)[superdb]> update dept set loc='sz' limit 1;
Query OK, 1 row affected (0.10 sec)
Rows matched: 1  Changed: 1  Warnings: 0

(root@localhost)[superdb]> select * from dept;
+--------+------------+---------+
| deptno | dname      | loc     |
+--------+------------+---------+
|     10 | ACCOUNTING | sz      |
|     20 | RESEARCH   | DALLAS  |
|     30 | SALES      | CHICAGO |
|     40 | OPERATIONS | BOSTON  |
+--------+------------+---------+
4 rows in set (0.00 sec)

(root@localhost)[superdb]> update dept set loc='NEW YORK' limit 1;
Query OK, 1 row affected (0.05 sec)
Rows matched: 1  Changed: 1  Warnings: 0

(root@localhost)[superdb]> update dept set loc='NEW YORK' where deptno=10;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

(root@localhost)[superdb]> select * from dept;
+--------+------------+----------+
| deptno | dname      | loc      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+
4 rows in set (0.00 sec)

(root@localhost)[superdb]> update dept set loc='NEW YORK' where deptno=10 limit 2;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

(root@localhost)[superdb]> select * from dept;
+--------+------------+----------+
| deptno | dname      | loc      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+
4 rows in set (0.00 sec)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • Pernyataan delete harus memenuhi kondisi berikut agar dapat dieksekusi dengan sukses:
    • Pernyataan delete juga menggunakan kolom indeks pada kondisi Where
    • Pernyataan delete menggunakan kolom indeks dan batas dalam kondisi di mana.
    • Pernyataan delete menggunakan di mana dan membatasi pada saat yang sama, kondisi di mana tidak perlu memiliki kolom indeks;
(root@localhost)[superdb]> insert into dept values(50,'sz','hk');
Query OK, 1 row affected (0.01 sec)

-- 同时使用 where 和 limit,此时 where 条件中可以有索引列
(root@localhost)[superdb]> delete from dept where deptno=50 limit 1;
Query OK, 1 row affected (0.00 sec)

(root@localhost)[superdb]> insert into dept values(50,'sz','hk');
Query OK, 1 row affected (0.00 sec)

-- 仅使用 where条件中是索引列
(root@localhost)[superdb]> delete from dept where deptno=50;
Query OK, 1 row affected (0.01 sec)

(root@localhost)[superdb]> insert into dept values(50,'sz','hk');
Query OK, 1 row affected (0.00 sec)

-- dname不是索引列,因此无法删除操作
(root@localhost)[superdb]> delete from dept where dname='sz';
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column. 

-- 同时使用 where 和 limit,此时 where 条件中没有索引列
(root@localhost)[superdb]> delete from dept where dname='sz' limit 1;
Query OK, 1 row affected (0.05 sec)

(root@localhost)[superdb]> select * from dept;
+--------+------------+----------+
| deptno | dname      | loc      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+
4 rows in set (0.00 sec)

(root@localhost)[superdb]> show index from dept;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| dept  |          0 | PRIMARY  |            1 | deptno      | A         |           4 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
1 row in set (0.13 sec)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

Jika kondisi di mana membawa kolom indeks, namun pengoptimal pada akhirnya memindai dan memilih seluruh tabel alih-alih indeks, kita dapat menggunakan force index([index_name]) untuk memberi tahu pengoptimal indeks mana yang akan digunakan untuk menghindari kemungkinan mengunci keseluruhan meja. bahaya tersembunyi yang disebabkan oleh meja.