Bạn có đang thêm MySQL vào danh sách các bộ kỹ năng cơ sở dữ liệu của mình không? Sau đó, câu lệnh MySQL UPDATE là một trong những lệnh bạn cần học.
Chúng tôi đang tiếp tục hành trình đến MySQL từ quan điểm SQL Server. Nó bắt đầu với CREATE TABLE, tiếp theo là INSERT và phần gần đây nhất là về DELETE. Hôm nay, UPDATE là tâm điểm của chúng tôi.
Sự khác biệt là tinh tế và dễ học. Nhưng cũng giống như các bài viết trước, mục tiêu của chúng tôi là giúp bạn thiết lập và chạy nhanh chóng. Nhưng trước khi tiếp tục, hãy làm rõ những mục sau:
- Các ví dụ được sử dụng ở đây được chạy trên MySQL 8.0.23 bằng công cụ lưu trữ InnoDB.
- Chúng tôi đã sử dụng SQL Server 2019.
Chuẩn bị dữ liệu mẫu
Chúng tôi không thể tiếp tục nếu không có dữ liệu mẫu. Tôi muốn đặt các nhà phát triển T-SQL ở nhà trong bài tập này. Vì vậy, hãy nhập một số bảng quen thuộc vào AdventureWorks cơ sở dữ liệu mẫu từ SQL Server:
- Sản phẩm
- SalesOrderHeader
- SalesOrderDetails
Để nhập các bảng này vào MySQL, tôi đã sử dụng dbForge Studio cho MySQL. Đây là các bước:
- Tạo cơ sở dữ liệu mới có tên là adventureworks2019 .
- Nhấp chuột phải vào adventureworks2019 và chọn Công cụ .
- Chọn Nhập dữ liệu . Một cửa sổ mới sẽ xuất hiện.
- Chọn ODBC . Bạn cần tạo DSN người dùng để kết nối với Máy chủ SQL của bạn và AdventureWorks cơ sở dữ liệu.
- Nhấp vào Tiếp theo .
- Chọn bảng bạn cần nhập, kết nối MySQL và cơ sở dữ liệu đích ( adventureworks2019 ).
- Nhấp vào Tiếp theo .
- Thay đổi cài đặt cột. Bạn cũng có thể xem dữ liệu mẫu. Bạn có thể bỏ qua điều này bằng cách nhấp vào Tiếp theo hoặc thay đổi cài đặt khi bạn thấy phù hợp.
- Nhấp vào Nhập .
- Nhập bảng tiếp theo bằng cách làm theo các hướng dẫn tương tự trên màn hình.
- Nhấp vào Hoàn tất .
Sau khi nhập các bảng này, bây giờ bạn đã sẵn sàng cho các ví dụ trong bài viết này. Vì vậy, hãy bắt đầu.
1. Khái niệm cơ bản về cú pháp
Cú pháp câu lệnh MySQL UPDATE như sau:
UPDATE [LOW_PRIORITY] [IGNORE] table_references
SET assignment_list
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
Tôi gần như có thể nghe thấy bạn sau khi đọc cú pháp:ƯU TIÊN THẤP, BỎ QUA, ĐẶT HÀNG THEO và GIỚI HẠN không phù hợp! Hãy bắt đầu thảo luận từ đầu.
Đầu tiên, LOW_PRIORITY là một từ khóa xa lạ với chúng tôi vì SQL Server không hỗ trợ nó. Đây là tùy chọn, nhưng nếu bạn bao gồm nó, các bản cập nhật sẽ bị trì hoãn cho đến khi tất cả các khách hàng khác không đọc bảng.
Một từ khóa khác của người ngoài hành tinh là BỎ QUA. Nó cũng là tùy chọn, nhưng nếu bạn bao gồm nó và xảy ra trùng lặp, thì sẽ không xảy ra lỗi. Để biết thêm các lỗi có thể bỏ qua, hãy xem liên kết này.
Sau đó, ĐẶT HÀNG THEO. Chúng tôi biết nó dùng để làm gì. Nhưng hãy thử nó trong SQL Server Management Studio và các dòng nguệch ngoạc sẽ xuất hiện bên dưới các từ khóa.
Cuối cùng là GIỚI HẠN. Điều này giống như TOP trong SQL Server. Thêm về điều này và ĐẶT HÀNG BẰNG trong phần sau.
Đây là những khác biệt rõ ràng. Đọc tiếp trong 2 phần phụ tiếp theo.
CẬP NHẬT MySQL Một Cột
Cập nhật một cột gần như tương tự. Vì vậy, ví dụ dưới đây sẽ tạo ra cùng một kết quả từ cả hai nền tảng cơ sở dữ liệu. Tuy nhiên, lưu ý rằng thay vì dấu gạch ngược, SQL Server sử dụng dấu ngoặc vuông.
-- MySQL UPDATE single column
UPDATE `production.product`
SET ReorderPoint = 650
WHERE ProductID = 316;
Đây là cú pháp T-SQL tương đương:
-- T-SQL UPDATE single column
UPDATE [Production].[Product]
SET ReorderPoint = 650
WHERE ProductID = 316;
Giá trị được gán cho một cột có thể là bất kỳ biểu thức giá trị đơn nào miễn là kiểu trả về giống với kiểu dữ liệu của cột.
CẬP NHẬT MySQL Nhiều Cột
Cập nhật nhiều cột cũng gần tương tự như T-SQL. Đây là một ví dụ:
UPDATE `production.product`
SET ReorderPoint = 650, SafetyStockLevel = 1200
WHERE ProductID = 316;
Để cập nhật nhiều cột, chỉ cần tách các cặp giá trị cột bằng dấu phẩy. Một lần nữa, sự khác biệt duy nhất ở đây là các thanh backticks.
Cho đến nay, đây là tất cả các bản cập nhật bảng đơn. Hãy chuyển sang CẬP NHẬT MySQL từ một bảng khác.
2. CẬP NHẬT MySQL với THAM GIA
Có những khác biệt nhỏ mà bạn sẽ thấy khi cập nhật bảng có các phép nối. Cách tốt nhất để hiển thị điều này là thông qua một ví dụ về việc sử dụng 3 bảng.
UPDATE `sales.salesorderdetail` sod
INNER JOIN `sales.salesorderheader` soh ON sod.SalesOrderID = soh.SalesOrderID
INNER JOIN `production.product` p ON sod.ProductID = p.ProductID
set UnitPrice = p.ListPrice
WHERE p.ProductID = 758
AND soh.OrderDate = '2012-04-30';
Lưu ý rằng một số mệnh đề được sắp xếp khác nhau khi so sánh với SQL Server. Các phép nối xuất hiện đầu tiên trước mệnh đề SET. Không có mệnh đề FROM nào cả. Như bạn có thể mong đợi, SQL Server Management Studio sẽ đặt các dòng nguệch ngoạc cho cú pháp vi phạm. Xem điều này và cú pháp T-SQL chính xác trong Hình 1 bên dưới.
Trước khi cập nhật, giá trị đơn giá là 874,7940 như trong Hình 2.
Sau khi cập nhật, UnitPrice được cập nhật từ Sản phẩm bảng của Danh sách Giá . Xem Hình 3.
Ngoài INNER JOIN, bạn có thể sử dụng LEFT hoặc RIGHT JOIN tùy theo yêu cầu của mình.
3. CẬP NHẬT MySQL với Truy vấn con
Bạn có thể sử dụng câu lệnh MySQL UPDATE từ một bảng khác bằng cách sử dụng truy vấn con. Có thể viết lại truy vấn với một phép nối trong phần trước bằng cách sử dụng một truy vấn con. Kết quả sẽ giống nhau. Đây là:
UPDATE `sales.salesorderdetail` sod
INNER JOIN `sales.salesorderheader` soh ON sod.SalesOrderID = soh.SalesOrderID
SET sod.UnitPrice = (select ListPrice from `production.product` WHERE ProductID = 758)
WHERE sod.ProductID = 758
AND soh.OrderDate = '2012-04-30';
Cách tiếp cận khác nhau, nhưng kết quả giống như trong Hình 3. Tuy nhiên, lưu ý rằng truy vấn con được sử dụng để cập nhật một cột phải trả về 1 giá trị.
Có một cách khác để diễn đạt câu lệnh CẬP NHẬT MySQL này.
4. CẬP NHẬT MySQL với CTE
Biểu thức bảng chung (CTE) được hỗ trợ trong cả MySQL và SQL Server. Nếu bạn không quen với CTE, hãy xem bài viết trước.
Bây giờ, đây là câu lệnh tương đương với CTE được sử dụng.
WITH priceIncrease AS
(
SELECT soh.SalesOrderID, p.ProductID, p.ListPrice
FROM `sales.salesorderdetail` sod
INNER JOIN `sales.salesorderheader` soh ON sod.SalesOrderID = soh.SalesOrderID
INNER JOIN `production.product` p ON sod.ProductID = p.ProductID
WHERE p.ProductID = 758
AND soh.OrderDate = '2012-04-30'
)
UPDATE `sales.salesorderdetail` s
INNER JOIN priceIncrease pi ON s.SalesOrderID = pi.SalesOrderID AND s.ProductID = pi.ProductID
SET s.UnitPrice = pi.ListPrice
SQL Server hỗ trợ khái niệm tương tự, nhưng không có dấu ngoặc đơn. Kết quả sẽ giống như trong Hình 3.
Bạn có thể hỏi, cách nào trong 3 cách tiếp cận tốt hơn? Chúng tôi sẽ so sánh thêm hiệu suất của chúng.
5. CẬP NHẬT MySQL với LIMIT
MySQL UPDATE có thể giới hạn số lượng hàng để cập nhật với từ khóa LIMIT. Giả sử chúng tôi muốn cập nhật 5 bản ghi trong Sản phẩm bàn. Chúng ta có thể diễn đạt tuyên bố như sau:
UPDATE `production.product` p
SET p.StandardCost = p.StandardCost + 10, p.ListPrice = p.ListPrice + 10
ORDER BY p.ProductID
LIMIT 5;
Điều này sẽ sắp xếp các bản ghi dựa trên ProductID , và sau đó cập nhật 5 bản ghi đầu tiên. Nó dừng sau bản ghi thứ 5.
Bản sao LIMIT của SQL Server là TOP. Tuy nhiên, bạn không thể chỉ thay đổi từ khóa LIMIT thành TOP và mong đợi nó sẽ hoạt động trong SQL Server. Đây là phiên bản được sửa đổi trong T-SQL sẽ cho kết quả tương tự:
UPDATE Production.Product
SET StandardCost += 10, ListPrice += 10
WHERE ProductID IN (SELECT TOP 5 ProductID
FROM Production.Product
ORDER BY ProductID)
Logic là một chút khác nhau. Nó cập nhật StandardCost và ListPrice dựa trên ProductID được tìm thấy trong truy vấn con. Mặt khác, truy vấn con trả về 5 bản ghi đầu tiên của Sản phẩm bảng được sắp xếp theo ProductID .
Mặc dù TOP cũng được hỗ trợ trong T-SQL UPDATE, ORDER BY thì không. Vì vậy, sử dụng TOP với UPDATE sẽ sửa đổi các bản ghi ngẫu nhiên. Cú pháp trên có thể áp dụng cho các bản ghi có thứ tự TOP.
Hiệu suất CẬP NHẬT MySQL
Trước đó, chúng tôi đã có một câu lệnh UPDATE với kết quả giống nhau mặc dù chúng tôi đã sử dụng các phương pháp khác nhau. Chúng tôi đã sử dụng JOIN, truy vấn con và CTE. Cái nào trong số họ sẽ hoạt động tốt nhất?
Ngoài ra còn có một kế hoạch thực thi trong MySQL bằng cách sử dụng từ khóa EXPLAIN. Cú pháp như sau:
EXPLAIN [FORMAT=JSON]
<SQL statement>
Nếu không có định dạng JSON, bạn có thông tin cơ bản như bảng, khóa chỉ mục được sử dụng và các hàng được quét. Khi định dạng JSON được chỉ định, bạn sẽ có thêm thông tin chi tiết. dbForge Studio cho MySQL bao gồm một Hồ sơ truy vấn ngoài kết quả GIẢI THÍCH. MySQL Workbench bao gồm GIẢI THÍCH Trực quan, nơi bạn có thể xem dạng đồ họa của kế hoạch dựa trên EXPLAIN FORMAT =JSON.
Bây giờ chúng ta đã biết các câu lệnh dòng lệnh và công cụ đồ họa, làm cách nào chúng ta có thể sử dụng chúng để so sánh các phương pháp khác nhau?
Trước khi chúng tôi tiếp tục, hãy để tôi thành thật. Trình độ thông thạo SQL Server của tôi cao hơn MySQL. Tôi có thể bỏ lỡ điều gì đó trên đường đi hoặc sai. Bạn có thể lấp đầy khoảng trống trong phần Nhận xét sau.
Phân tích kết quả GIẢI THÍCH để CẬP NHẬT với THAM GIA
Lần đầu tiên tôi chạy câu lệnh MySQL UPDATE với JOIN, mất 11,3 giây để cập nhật 24 hàng. Thật không thể tin được, phải không?
Đây là những gì đã xảy ra trong dbForge Studio. Xem Hình 4 bên dưới.
Hình 4 cho chúng ta biết điều gì?
- 3 bí danh bảng được sử dụng ở đó. Cả 3 đều có kiểu truy cập TẤT CẢ. Nó có nghĩa là MySQL đã sử dụng Bảng quét cho cả 3.
- Nhìn vào phím cột. Không có gì được hiển thị trên cả 3 bảng, có nghĩa là không có khóa chỉ mục nào được sử dụng. Điều này hỗ trợ điểm trước đó của Quét bảng.
- Cuối cùng, hàng cột. Nó cho biết có bao nhiêu hàng mà MySQL tin rằng nó sẽ quét để đạt được kết quả cuối cùng. Đối với 24 hàng được cập nhật, hàng nghìn hàng đã được quét cho SalesOrderHeader và SalesOrderDetails . Trong khi đó, tất cả các hàng của Sản phẩm bảng đã được quét.
Tôi vò đầu bứt tai khi biết điều này. Tôi nhận ra rằng khi tôi nhập bảng từ SQL Server, chỉ cấu trúc bảng và dữ liệu được nhập chứ không phải chỉ mục .
Vì vậy, tôi đã tạo các chỉ mục và khóa chính thích hợp trong dbForge Studio. Đây là những gì tôi đã tạo:
- Tôi đã tạo ProductID trong Sản phẩm bảng một khóa chính.
- Tôi cũng đã thêm SalesOrderID làm khóa chính trong SalesOrderHeader bàn. Sau đó, tôi đã tạo chỉ mục cho Ngày đặt hàng quá.
- Cuối cùng, tôi đã tạo SalesOrderDetailID trong SalesOrderDetail bảng một khóa chính. Tôi cũng đã thêm một chỉ mục cho SalesOrderID và ProductID các cột của bảng này.
Sau đó, tôi đã tạo một kế hoạch thực thi mới cho cùng một truy vấn để xem các cải tiến. Kết quả?
TỐC ĐỘ BOOST SAU KHI THÊM CÁC CHỈ SỐ
Thời gian thi triển giảm từ 11,3 giây xuống 0,019 giây. Rất tuyệt!
Hãy kiểm tra gói mới bằng cách sử dụng dbForge Studio trong Hình 5 bên dưới.
Hình 5 cho chúng ta biết điều gì?
- Quyền truy cập loại của 3 bảng đã được thay đổi. 2 giá trị cần tránh ở đây là ALL và INDEX, đặc biệt là trên các bảng lớn. ALL là quét bảng và INDEX là quét chỉ mục.
- Chìa khóa cột bây giờ bao gồm các chỉ mục được sử dụng. Điều này là tốt. Tất cả các chỉ mục được thêm vào đều đã được sử dụng.
- Hàng cột bây giờ hiển thị các số liệu nhỏ hơn. Các chỉ mục được thêm vào làm giảm rất nhiều I / O trên truy vấn của chúng tôi.
Để biết thêm thông tin về các chi tiết và giá trị GIẢI THÍCH, hãy xem tài liệu chính thức này.
Nhưng điều này so sánh với MySQL UPDATE với truy vấn con như thế nào?
Phân tích kết quả GIẢI THÍCH để CẬP NHẬT với Truy vấn con
Truy vấn trước đó để cập nhật UnitPrice có một thay thế truy vấn khác, đang sử dụng một truy vấn con. Nó so sánh với JOIN như thế nào? Xem Hình 6 bên dưới.
Hình 6 cho thấy:
- Giá trị cột kiểu, khóa và hàng giống nhau so với khi sử dụng JOIN. Điều này là hợp lý vì nó sẽ có cùng kết quả.
- Thời gian thực hiện nhanh hơn một chút. Tuy nhiên, điều này sẽ không xảy ra mọi lúc. Nó phụ thuộc vào các nguồn hiện tại có sẵn. Chênh lệch tốc độ cũng không đáng kể. Bạn hoàn toàn không cảm thấy điều đó.
Một cách khác là sử dụng EXPLAIN FORMAT =JSON để biết thêm thông tin về kế hoạch. Khi kiểm tra, chi phí truy vấn (84,79) và giá trị thông tin chi phí là như nhau.
Bây giờ, hãy so sánh nó với MySQL UPDATE với CTE.
Phân tích kết quả GIẢI THÍCH để CẬP NHẬT với CTE
Sử dụng CTE làm cơ sở để cập nhật Đơn giá giống như việc có một bảng tạm thời trước và sau đó tham gia bảng tạm thời thành SalesOrderDetails . Thoạt nhìn, có vẻ như đây không phải là một lựa chọn tốt so với hai lựa chọn đầu tiên. Nhưng nó cho chúng ta thấy rằng có thể có bản cập nhật trong MySQL bằng CTE. Nó có thể là một lựa chọn tốt trong các tình huống khác. Dù sao, hãy có kết quả GIẢI THÍCH cho phương pháp này.
Nếu bạn không có dbForge Studio cho MySQL, bạn có thể thử tạo kết quả GIẢI THÍCH bằng lệnh trong bất kỳ trình chỉnh sửa nào khác. Đây là một ví dụ:
EXPLAIN
WITH priceIncrease AS
(
SELECT soh.SalesOrderID, p.ProductID, p.ListPrice
FROM `sales.salesorderdetail` sod
INNER JOIN `sales.salesorderheader` soh ON sod.SalesOrderID = soh.SalesOrderID
INNER JOIN `production.product` p ON sod.ProductID = p.ProductID
WHERE p.ProductID = 758
AND soh.OrderDate = '2012-04-30'
)
UPDATE `sales.salesorderdetail` s
INNER JOIN priceIncrease pi ON s.SalesOrderID = pi.SalesOrderID AND s.ProductID = pi.ProductID
SET s.UnitPrice = pi.ListPrice
Kết quả như hình 7 bên dưới.
Hình 7 cho thấy:
- 4 bảng đã được sử dụng thay vì 3. Lần sử dụng đầu tiên của SalesOrderDetail trong CTE và sau đó là trong câu lệnh UPDATE.
- Nhiều bảng hơn có nghĩa là nhiều hàng hơn so với 2 cách tiếp cận trước đó.
Đáng ngạc nhiên, điều này chạy ở 0,015 giây (không được hiển thị trong hình). Điều này cũng tương tự với việc sử dụng một truy vấn con. Tuy nhiên, điều đó sẽ không xảy ra mọi lúc. Nó phụ thuộc vào tài nguyên hệ thống có sẵn tại thời điểm thực thi.
Tổng chi phí truy vấn là 166,69. Nó cao hơn 2 cách tiếp cận trước. Chi phí truy vấn càng thấp thì hiệu suất càng tốt theo thời gian.
Bài học rút ra
Chúng tôi đã đi sâu vào sự khác biệt giữa MySQL và câu lệnh UPDATE của SQL Server. Chúng tôi đã biết cách thực hiện khi cập nhật
- một cột duy nhất
- nhiều cột
- bảng có tham gia
- cột sử dụng truy vấn con
- bảng có CTE
- với một LIMIT
Trong bài đăng này, bạn cũng đã biết trước về GIẢI THÍCH và cách sử dụng nó để so sánh các phương pháp CẬP NHẬT khác nhau.
Tôi hy vọng điều này có thể hữu ích cho bạn khi bạn học MySQL đến từ SQL Server. Nếu bạn thích bài đăng này, hãy chia sẻ nó trên các nền tảng mạng xã hội ưa thích của bạn. Và nếu thiếu điều gì đó, hãy cho chúng tôi biết trong phần Nhận xét.
Chúc bạn viết mã vui vẻ!