Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Hiểu các bế tắc trong MySQL &PostgreSQL

Làm việc với cơ sở dữ liệu, kiểm soát đồng thời là khái niệm đảm bảo rằng các giao dịch cơ sở dữ liệu được thực hiện đồng thời mà không vi phạm tính toàn vẹn của dữ liệu.

Có rất nhiều lý thuyết và cách tiếp cận khác nhau xung quanh khái niệm này và cách thực hiện nó, nhưng chúng tôi sẽ đề cập ngắn gọn đến cách PostgreSQL và MySQL (khi sử dụng InnoDB) xử lý nó và một vấn đề phổ biến có thể phát sinh trong các hệ thống đồng thời cao:bế tắc.

Các công cụ này thực hiện điều khiển đồng thời bằng cách sử dụng một phương pháp được gọi là MVCC (Điều khiển đồng thời đa vũ trụ). Trong phương pháp này, khi một mục đang được cập nhật, các thay đổi sẽ không ghi đè lên dữ liệu gốc mà thay vào đó, một phiên bản mới của mục (với các thay đổi) sẽ được tạo. Vì vậy, chúng tôi sẽ có một số phiên bản của mục được lưu trữ.

Một trong những ưu điểm chính của mô hình này là các khóa có được để truy vấn (đọc) dữ liệu không xung đột với các khóa có được để ghi dữ liệu và do đó, việc đọc không bao giờ chặn việc ghi và việc ghi không bao giờ chặn việc đọc.

Nhưng, nếu một số phiên bản của cùng một mặt hàng được lưu trữ, thì một giao dịch sẽ thấy phiên bản nào của nó? Để trả lời câu hỏi đó, chúng ta cần xem xét lại khái niệm về sự cô lập giao dịch. Các giao dịch chỉ định một mức cô lập, xác định mức độ mà một giao dịch phải được cô lập khỏi các sửa đổi tài nguyên hoặc dữ liệu được thực hiện bởi các giao dịch khác. Mức độ này liên quan trực tiếp đến việc khóa được tạo ra bởi một giao dịch và do đó, vì nó có thể được chỉ định ở cấp độ giao dịch, nó có thể xác định tác động mà một giao dịch đang chạy có thể có đối với các giao dịch đang chạy khác.

Đây là một chủ đề rất thú vị và dài, mặc dù chúng ta sẽ không đi vào quá nhiều chi tiết trong blog này. Chúng tôi khuyên bạn nên sử dụng tài liệu chính thức của PostgreSQL và MySQL để đọc thêm về chủ đề này.

Vì vậy, tại sao chúng ta lại đi vào các chủ đề trên khi giải quyết bế tắc? Bởi vì các lệnh sql sẽ tự động có được các khóa để đảm bảo hành vi MVCC và loại khóa có được phụ thuộc vào sự cô lập giao dịch được xác định.

Có một số loại khóa (một lần nữa là một chủ đề dài và thú vị khác để xem xét cho PostgreSQL và MySQL) nhưng, điều quan trọng về chúng, là cách chúng tương tác (chính xác nhất, cách chúng xung đột) với nhau. Tại sao vậy? Bởi vì hai giao dịch không thể giữ khóa các chế độ xung đột trên cùng một đối tượng cùng một lúc. Và một chi tiết không nhỏ, sau khi có được, khóa thường được giữ cho đến khi kết thúc giao dịch.

Đây là một ví dụ PostgreSQL về cách các loại khóa xung đột với nhau:

Xung đột kiểu khóa PostgreSQL

Và đối với MySQL:

Xung đột kiểu khóa MySQL

X =ổ khóa độc quyền IX =khóa độc quyền
S =shared lock IS =ý định chia sẻ khóa

Vì vậy, điều gì sẽ xảy ra khi tôi có hai giao dịch đang chạy muốn giữ các khóa xung đột trên cùng một đối tượng cùng một lúc? Một trong số họ sẽ nhận được khóa và người kia sẽ phải đợi.

Vì vậy, bây giờ chúng tôi có thể thực sự hiểu những gì đang xảy ra trong thời kỳ bế tắc.

Thế nào là bế tắc? Như bạn có thể tưởng tượng, có một số định nghĩa cho deadlock cơ sở dữ liệu, nhưng tôi thích định nghĩa sau vì tính đơn giản của nó.

Bế tắc cơ sở dữ liệu là một tình huống trong đó hai hoặc nhiều giao dịch đang chờ đợi một giao dịch khác từ bỏ khóa.

Vì vậy, ví dụ, tình huống sau đây sẽ dẫn chúng ta đến một bế tắc:

Ví dụ về chốt chặn

Tại đây, ứng dụng A có một khóa trên bảng 1 hàng 1 để thực hiện cập nhật.

Đồng thời ứng dụng B bị khóa trên bảng 2 hàng 2.

Bây giờ ứng dụng A cần lấy khóa trên bảng 2 hàng 2, để tiếp tục thực hiện và kết thúc giao dịch, nhưng nó không thể lấy khóa vì ứng dụng B. Ứng dụng A cần đợi ứng dụng B giải phóng nó. .

Nhưng ứng dụng B cần có một khóa trên bảng 1 hàng 1, để tiếp tục thực hiện và kết thúc giao dịch, nhưng nó không thể nhận được khóa vì nó được giữ bởi ứng dụng A.

Vì vậy, ở đây chúng tôi đang ở trong một tình huống bế tắc. Ứng dụng A đang đợi tài nguyên do ứng dụng B nắm giữ để kết thúc và ứng dụng B đang chờ tài nguyên do ứng dụng A. nắm giữ, vậy làm thế nào để tiếp tục? Công cụ cơ sở dữ liệu sẽ phát hiện bế tắc và loại bỏ một trong các giao dịch, bỏ chặn giao dịch kia và tạo ra lỗi bế tắc trên giao dịch đã bị hủy.

Hãy kiểm tra một số ví dụ về deadlock của PostgreSQL và MySQL:

PostgreSQL

Giả sử chúng ta có một cơ sở dữ liệu thử nghiệm với thông tin từ các quốc gia trên thế giới.

world=# SELECT code,region,population FROM country WHERE code IN ('NLD','AUS');
code |          region           | population
------+---------------------------+------------
NLD  | Western Europe            |   15864000
AUS  | Australia and New Zealand |   18886000
(2 rows)

Chúng tôi có hai phiên muốn thực hiện thay đổi đối với cơ sở dữ liệu.

Phiên đầu tiên sẽ sửa đổi trường vùng cho mã NLD và trường dân số cho mã AUS.

Phiên thứ hai sẽ sửa đổi trường vùng cho mã AUS và trường dân số cho mã NLD.

Dữ liệu bảng:

code: NLD
region: Western Europe
population: 15864000
code: AUS
region: Australia and New Zealand
population: 18886000

Buổi 1:

world=# BEGIN;
BEGIN
world=# UPDATE country SET region='Europe' WHERE code='NLD';
UPDATE 1

Phiên 2:

world=# BEGIN;
BEGIN
world=# UPDATE country SET region='Oceania' WHERE code='AUS';
UPDATE 1
world=# UPDATE country SET population=15864001 WHERE code='NLD';

Phần 2 sẽ bị treo khi Phần 1 kết thúc.

Buổi 1:

world=# UPDATE country SET population=18886001 WHERE code='AUS';

ERROR:  deadlock detected
DETAIL:  Process 1181 waits for ShareLock on transaction 579; blocked by process 1148.
Process 1148 waits for ShareLock on transaction 578; blocked by process 1181.
HINT:  See server log for query details.
CONTEXT:  while updating tuple (0,15) in relation "country"

Ở đây chúng tôi có bế tắc của chúng tôi. Hệ thống đã phát hiện ra bế tắc và kết thúc phiên 1.

Phiên 2:

world=# BEGIN;
BEGIN
world=# UPDATE country SET region='Oceania' WHERE code='AUS';
UPDATE 1
world=# UPDATE country SET population=15864001 WHERE code='NLD';
UPDATE 1

Và chúng tôi có thể kiểm tra xem phiên thứ hai đã kết thúc đúng cách sau khi phát hiện thấy bế tắc chưa và phiên 1 đã bị hủy (do đó, khóa đã được giải phóng).

Để biết thêm chi tiết, chúng tôi có thể xem nhật ký trong máy chủ PostgreSQL của chúng tôi:

2018-05-16 12:56:38.520 -03 [1181] ERROR:  deadlock detected
2018-05-16 12:56:38.520 -03 [1181] DETAIL:  Process 1181 waits for ShareLock on transaction 579; blocked by process 1148.
       Process 1148 waits for ShareLock on transaction 578; blocked by process 1181.
       Process 1181: UPDATE country SET population=18886001 WHERE code='AUS';
       Process 1148: UPDATE country SET population=15864001 WHERE code='NLD';
2018-05-16 12:56:38.520 -03 [1181] HINT:  See server log for query details.
2018-05-16 12:56:38.520 -03 [1181] CONTEXT:  while updating tuple (0,15) in relation "country"
2018-05-16 12:56:38.520 -03 [1181] STATEMENT:  UPDATE country SET population=18886001 WHERE code='AUS';
2018-05-16 12:59:50.568 -03 [1181] ERROR:  current transaction is aborted, commands ignored until end of transaction block

Tại đây, chúng ta sẽ có thể xem các lệnh thực tế đã được phát hiện khi deadlock.

Tải xuống Báo cáo chính thức hôm nay Quản lý &Tự động hóa PostgreSQL với ClusterControlTìm hiểu về những điều bạn cần biết để triển khai, giám sát, quản lý và mở rộng PostgreSQLTải xuống Báo cáo chính thức

MySQL

Để mô phỏng một deadlock trong MySQL, chúng ta có thể làm như sau.

Như với PostgreSQL, giả sử chúng ta có một cơ sở dữ liệu thử nghiệm với thông tin về diễn viên và phim cùng những thứ khác.

mysql> SELECT first_name,last_name FROM actor WHERE actor_id IN (1,7);
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| PENELOPE   | GUINESS   |
| GRACE      | MOSTEL    |
+------------+-----------+
2 rows in set (0.00 sec)

Chúng tôi có hai quy trình muốn thực hiện các thay đổi đối với cơ sở dữ liệu.

Quá trình đầu tiên sẽ sửa đổi trường first_name cho Actor_id 1 và trường last_name cho Actor_id 7.

Quá trình thứ hai sẽ sửa đổi trường first_name cho Actor_id 7 và trường last_name cho Actor_id 1.

Dữ liệu bảng:

actor_id: 1
first_name: PENELOPE
last_name: GUINESS
actor_id: 7
first_name: GRACE
last_name: MOSTEL

Buổi 1:

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE actor SET first_name='GUINESS' WHERE actor_id='1';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Phiên 2:

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE actor SET first_name='MOSTEL' WHERE actor_id='7';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> UPDATE actor SET last_name='PENELOPE' WHERE actor_id='1';

Phần 2 sẽ bị treo khi Phần 1 kết thúc.

Buổi 1:

mysql> UPDATE actor SET last_name='GRACE' WHERE actor_id='7';

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

Ở đây chúng tôi có bế tắc của chúng tôi. Hệ thống đã phát hiện ra bế tắc và kết thúc phiên 1.

Phiên 2:

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE actor SET first_name='MOSTEL' WHERE actor_id='7';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> UPDATE actor SET last_name='PENELOPE' WHERE actor_id='1';
Query OK, 1 row affected (8.52 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Như chúng ta có thể thấy trong lỗi, như chúng ta đã thấy đối với PostgreSQL, có một bế tắc giữa cả hai quy trình.

Để biết thêm chi tiết, chúng ta có thể sử dụng lệnh SHOW ENGINE INNODB STATUS \ G:

mysql> SHOW ENGINE INNODB STATUS\G
------------------------
LATEST DETECTED DEADLOCK
------------------------
2018-05-16 18:55:46 0x7f4c34128700
*** (1) TRANSACTION:
TRANSACTION 1456, ACTIVE 33 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 54, OS thread handle 139965388506880, query id 15876 localhost root updating
UPDATE actor SET last_name='PENELOPE' WHERE actor_id='1'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 23 page no 3 n bits 272 index PRIMARY of table `sakila`.`actor` trx id 1456 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 2; hex 0001; asc   ;;
1: len 6; hex 0000000005af; asc       ;;
2: len 7; hex 2d000001690110; asc -   i  ;;
3: len 7; hex 4755494e455353; asc GUINESS;;
4: len 7; hex 4755494e455353; asc GUINESS;;
5: len 4; hex 5afca8b3; asc Z   ;;

*** (2) TRANSACTION:
TRANSACTION 1455, ACTIVE 47 sec starting index read, thread declared inside InnoDB 5000
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 53, OS thread handle 139965267871488, query id 16013 localhost root updating
UPDATE actor SET last_name='GRACE' WHERE actor_id='7'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 23 page no 3 n bits 272 index PRIMARY of table `sakila`.`actor` trx id 1455 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 2; hex 0001; asc   ;;
1: len 6; hex 0000000005af; asc       ;;
2: len 7; hex 2d000001690110; asc -   i  ;;
3: len 7; hex 4755494e455353; asc GUINESS;;
4: len 7; hex 4755494e455353; asc GUINESS;;
5: len 4; hex 5afca8b3; asc Z   ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 23 page no 3 n bits 272 index PRIMARY of table `sakila`.`actor` trx id 1455 lock_mode X locks rec but not gap waiting
Record lock, heap no 202 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 2; hex 0007; asc   ;;
1: len 6; hex 0000000005b0; asc       ;;
2: len 7; hex 2e0000016a0110; asc .   j  ;;
3: len 6; hex 4d4f5354454c; asc MOSTEL;;
4: len 6; hex 4d4f5354454c; asc MOSTEL;;
5: len 4; hex 5afca8c1; asc Z   ;;

*** WE ROLL BACK TRANSACTION (2)

Dưới tiêu đề "KHÓA CHẾT ĐƯỢC PHÁT HIỆN MỚI NHẤT", chúng ta có thể xem chi tiết về bế tắc của mình.

Để xem chi tiết về bế tắc trong nhật ký lỗi mysql, chúng tôi phải bật tùy chọn innodb_print_all_deadlocks trong cơ sở dữ liệu của chúng tôi.

mysql> set global innodb_print_all_deadlocks=1;
Query OK, 0 rows affected (0.00 sec)

Lỗi nhật ký MySQL:

2018-05-17T18:36:58.341835Z 12 [Note] InnoDB: Transactions deadlock detected, dumping detailed information.
2018-05-17T18:36:58.341869Z 12 [Note] InnoDB:
*** (1) TRANSACTION:
 
TRANSACTION 1812, ACTIVE 42 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 140515492943616, query id 8467 localhost root updating
UPDATE actor SET last_name='PENELOPE' WHERE actor_id='1'
2018-05-17T18:36:58.341945Z 12 [Note] InnoDB: *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
 
RECORD LOCKS space id 23 page no 3 n bits 272 index PRIMARY of table `sakila`.`actor` trx id 1812 lock_mode X locks rec but not gap waiting
Record lock, heap no 204 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 2; hex 0001; asc   ;;
1: len 6; hex 000000000713; asc       ;;
2: len 7; hex 330000016b0110; asc 3   k  ;;
3: len 7; hex 4755494e455353; asc GUINESS;;
4: len 7; hex 4755494e455353; asc GUINESS;;
5: len 4; hex 5afdcb89; asc Z   ;;
 
2018-05-17T18:36:58.342347Z 12 [Note] InnoDB: *** (2) TRANSACTION:
 
TRANSACTION 1811, ACTIVE 65 sec starting index read, thread declared inside InnoDB 5000
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 12, OS thread handle 140515492677376, query id 9075 localhost root updating
UPDATE actor SET last_name='GRACE' WHERE actor_id='7'
2018-05-17T18:36:58.342409Z 12 [Note] InnoDB: *** (2) HOLDS THE LOCK(S):
 
RECORD LOCKS space id 23 page no 3 n bits 272 index PRIMARY of table `sakila`.`actor` trx id 1811 lock_mode X locks rec but not gap
Record lock, heap no 204 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 2; hex 0001; asc   ;;
1: len 6; hex 000000000713; asc       ;;
2: len 7; hex 330000016b0110; asc 3   k  ;;
3: len 7; hex 4755494e455353; asc GUINESS;;
4: len 7; hex 4755494e455353; asc GUINESS;;
5: len 4; hex 5afdcb89; asc Z   ;;
 
2018-05-17T18:36:58.342793Z 12 [Note] InnoDB: *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
 
RECORD LOCKS space id 23 page no 3 n bits 272 index PRIMARY of table `sakila`.`actor` trx id 1811 lock_mode X locks rec but not gap waiting
Record lock, heap no 205 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 2; hex 0007; asc   ;;
1: len 6; hex 000000000714; asc       ;;
2: len 7; hex 340000016c0110; asc 4   l  ;;
3: len 6; hex 4d4f5354454c; asc MOSTEL;;
4: len 6; hex 4d4f5354454c; asc MOSTEL;;
5: len 4; hex 5afdcba0; asc Z   ;;
 
2018-05-17T18:36:58.343105Z 12 [Note] InnoDB: *** WE ROLL BACK TRANSACTION (2)

Xem xét những gì chúng ta đã tìm hiểu ở trên về lý do tại sao deadlock xảy ra, bạn có thể thấy rằng chúng ta không thể làm gì nhiều ở phía cơ sở dữ liệu để tránh chúng. Dù sao, với tư cách là DBA, nhiệm vụ của chúng tôi là thực sự bắt chúng, phân tích chúng và cung cấp phản hồi cho nhà phát triển.

Thực tế là những lỗi này xảy ra riêng cho từng ứng dụng, vì vậy bạn sẽ cần phải kiểm tra từng lỗi một và không có hướng dẫn cho bạn biết cách khắc phục sự cố này. Hãy ghi nhớ điều này, có một số điều bạn có thể tìm kiếm.

Mẹo để điều tra và tránh bế tắc

Tìm kiếm các giao dịch dài hạn. Vì các khóa thường được giữ cho đến khi kết thúc giao dịch, giao dịch càng lâu thì tài nguyên càng bị khóa lâu hơn. Nếu có thể, hãy cố gắng chia các giao dịch lâu dài thành các giao dịch nhỏ hơn / nhanh hơn.

Đôi khi không thể thực sự phân chia các giao dịch, vì vậy công việc nên tập trung vào việc cố gắng thực hiện các hoạt động đó theo một thứ tự nhất quán mỗi lần, do đó, các giao dịch tạo thành hàng đợi được xác định rõ ràng và không bị bế tắc.

Một giải pháp khác mà bạn cũng có thể đề xuất là thêm logic thử lại vào ứng dụng (tất nhiên, hãy cố gắng giải quyết vấn đề cơ bản trước) theo cách mà nếu xảy ra bế tắc, ứng dụng sẽ chạy lại các lệnh tương tự.

Kiểm tra các mức cô lập được sử dụng, đôi khi bạn thử bằng cách thay đổi chúng. Tìm kiếm các lệnh như CHỌN CẬP NHẬT và CHỌN ĐỂ CHIA SẺ, vì chúng tạo ra các khóa rõ ràng và đánh giá xem chúng có thực sự cần thiết hay không hoặc bạn có thể làm việc với ảnh chụp nhanh dữ liệu cũ hơn. Một điều bạn có thể thử nếu không thể loại bỏ các lệnh này là sử dụng mức cách ly thấp hơn, chẳng hạn như READ COMMITTED.

Tất nhiên, hãy luôn thêm các chỉ mục được chọn tốt vào bảng của bạn. Sau đó, các truy vấn của bạn cần phải quét ít bản ghi chỉ mục hơn và do đó đặt ít khóa hơn.

Ở cấp độ cao hơn, với tư cách là DBA, bạn có thể thực hiện một số biện pháp phòng ngừa để giảm thiểu việc khóa nói chung. Để đặt tên cho một ví dụ, trong trường hợp này đối với PostgreSQL, bạn có thể tránh thêm một giá trị mặc định trong cùng một lệnh mà bạn sẽ thêm một cột. Việc thay đổi một bảng sẽ nhận được một khóa thực sự linh hoạt và việc đặt giá trị mặc định cho nó sẽ thực sự cập nhật các hàng hiện có có giá trị null, khiến cho thao tác này thực sự mất nhiều thời gian. Vì vậy, nếu bạn chia thao tác này thành nhiều lệnh, thêm cột, thêm giá trị mặc định, cập nhật giá trị null, bạn sẽ giảm thiểu tác động khóa.

Tất nhiên, có rất nhiều mẹo như thế này mà các DBA có được khi thực hành (tạo chỉ mục đồng thời, tạo chỉ mục pk riêng trước khi thêm pk, v.v.), nhưng điều quan trọng là học và hiểu "cách suy nghĩ "và luôn để giảm thiểu tác động khóa của các hoạt động chúng tôi đang thực hiện.

Tóm tắt

Hy vọng rằng blog này đã cung cấp cho bạn những thông tin hữu ích về các deadlock cơ sở dữ liệu và cách khắc phục chúng. Vì không có cách nào chắc chắn để tránh bế tắc, nên biết cách hoạt động của chúng có thể giúp bạn nắm bắt chúng trước khi chúng gây hại cho các phiên bản cơ sở dữ liệu của bạn. Các giải pháp phần mềm như ClusterControl có thể giúp bạn đảm bảo rằng cơ sở dữ liệu của bạn luôn hoạt động tốt. ClusterControl đã giúp đỡ hàng trăm doanh nghiệp - bạn sẽ là doanh nghiệp tiếp theo chứ? Tải xuống bản dùng thử miễn phí của ClusterControl ngay hôm nay để xem nó có phù hợp với nhu cầu cơ sở dữ liệu của bạn không.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Câu hỏi phân biệt chữ hoa chữ thường varchar duy nhất trong SQL

  2. Lộ trình học MySQL

  3. Truy vấn SELECT trả về 1 hàng từ mỗi nhóm

  4. Sự khác biệt giữa =null và IS NULL là gì?

  5. Dấu thời gian với độ chính xác mili giây:Cách lưu chúng trong MySQL