大家好,願神的平安、憐憫、祝福臨到你們
SQL(結構化查詢語言)是管理和操作關係資料庫的重要工具。雖然基本的 SQL 技能可以幫助您入門,但高級 SQL 技術可以大大增強您處理複雜查詢和優化資料庫效能的能力。本文深入探討高階 SQL 主題,重點在於複雜的查詢最佳化策略、高階聯結類型以及SELECT
語句的複雜性。
最佳化 SQL 查詢是資料庫管理員和開發人員的關鍵技能。進階查詢最佳化超越了基本索引和查詢重構,還包括一系列複雜的技術。
了解查詢的執行計劃對於最佳化至關重要。執行計劃顯示 SQL 引擎如何執行查詢,揭示潛在的瓶頸。
EXPLAIN
語句提供對查詢執行方式的深入了解,使您能夠辨識效率低下的情況。 EXPLAIN SELECT column1, column2 FROM table_name WHERE condition;
ANALYZE
語句與EXPLAIN
結合使用,執行查詢並提供執行時統計訊息,從而更深入地了解查詢性能。 EXPLAIN ANALYZE SELECT column1, column2 FROM table_name WHERE condition;
子查詢有時可以替換為更有效率的聯結或WITH
子句(通用表表達式)。
-- Subquery
SELECT * FROM table1 WHERE column1 IN (SELECT column1 FROM table2);
-- Equivalent Join
SELECT table1.* FROM table1 INNER JOIN table2 ON table1.column1 = table2.column1;
WITH CTE AS (
SELECT column1, column2 FROM table_name WHERE condition
)
SELECT * FROM CTE WHERE another_condition;
進階索引策略包括使用複合索引和覆蓋索引。
CREATE INDEX idx_composite ON table_name (column1, column2);
CREATE INDEX idx_covering ON table_name (column1, column2, column3);
將大表劃分為更小、更易於管理的部分可以透過限制掃描的資料量來提高查詢效能。
CREATE TABLE orders (
order_id INT,
order_date DATE,
...
) PARTITION BY RANGE (order_date) (
PARTITION p0 VALUES LESS THAN ('2024-01-01'),
PARTITION p1 VALUES LESS THAN ('2025-01-01'),
...
);
CREATE TABLE users (
user_id INT,
username VARCHAR(255),
...
) PARTITION BY HASH(user_id) PARTITIONS 4;
CREATE TABLE sales (
sale_id INT,
region VARCHAR(255),
...
) PARTITION BY LIST (region) (
PARTITION p0 VALUES IN ('North', 'South'),
PARTITION p1 VALUES IN ('East', 'West')
);
物化視圖實體儲存查詢結果,並且可以定期刷新,從而提高頻繁執行的複雜查詢的效能。
CREATE MATERIALIZED VIEW sales_summary AS
SELECT region, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY region;
REFRESH MATERIALIZED VIEW sales_summary;
在 MySQL 中,存在視圖,但物化視圖本身並不存在。 MySQL支援標準視圖,這些視圖是儲存查詢定義並在查詢時動態產生結果集的虛擬表。但是,它沒有對物化視圖的內建支持,物化視圖物理儲存結果集。
您可以使用CREATE VIEW
語句在 MySQL 中建立視圖。這是一個例子:
CREATE VIEW ActiveCustomers AS
SELECT CustomerID, CustomerName, ContactName, Country
FROM Customers
WHERE Status = 'Active';
這將建立一個名為ActiveCustomers
的視圖,其中僅包含Customers
表中的活動客戶。查詢此視圖如下所示:
SELECT * FROM ActiveCustomers;
可以使用CREATE OR REPLACE VIEW
語句更新檢視:
CREATE OR REPLACE VIEW ActiveCustomers AS
SELECT CustomerID, CustomerName, ContactName, Country
FROM Customers
WHERE Status = 'Active' AND Country = 'USA';
這會將ActiveCustomers
檢視修改為僅包含來自美國的活躍客戶。
您可以使用DROP VIEW
語句刪除檢視:
DROP VIEW ActiveCustomers;
MySQL 本身不支援物化視圖,但有一些變通方法可以實現類似的功能。這裡有幾種方法:
一種常見的方法是建立一個表來儲存查詢結果並使用計劃事件(cron 作業)或觸發器定期更新它。
首先,建立一個表格來儲存結果:
CREATE TABLE MaterializedActiveCustomers AS
SELECT CustomerID, CustomerName, ContactName, Country
FROM Customers
WHERE Status = 'Active';
使用計劃事件定期更新表。此範例使用 MySQL 事件每小時更新一次表格:
CREATE EVENT UpdateMaterializedActiveCustomers
ON SCHEDULE EVERY 1 HOUR
DO
BEGIN
DELETE FROM MaterializedActiveCustomers;
INSERT INTO MaterializedActiveCustomers
SELECT CustomerID, CustomerName, ContactName, Country
FROM Customers
WHERE Status = 'Active';
END;
此事件每小時都會清除MaterializedActiveCustomers
表並使用最新的活躍客戶重新填充。
另一種方法是使用觸發器使表與基底表保持同步。然而,這可能會變得複雜,對於大型資料集可能效率不高。
首先,建立表:
CREATE TABLE MaterializedActiveCustomers AS
SELECT CustomerID, CustomerName, ContactName, Country
FROM Customers
WHERE Status = 'Active';
建立觸發器以保持物化表更新:
DELIMITER //
CREATE TRIGGER after_customer_insert
AFTER INSERT ON Customers
FOR EACH ROW
BEGIN
IF NEW.Status = 'Active' THEN
INSERT INTO MaterializedActiveCustomers (CustomerID, CustomerName, ContactName, Country)
VALUES (NEW.CustomerID, NEW.CustomerName, NEW.ContactName, NEW.Country);
END IF;
END //
CREATE TRIGGER after_customer_update
AFTER UPDATE ON Customers
FOR EACH ROW
BEGIN
IF OLD.Status = 'Active' AND NEW.Status != 'Active' THEN
DELETE FROM MaterializedActiveCustomers WHERE CustomerID = OLD.CustomerID;
ELSEIF NEW.Status = 'Active' THEN
REPLACE INTO MaterializedActiveCustomers (CustomerID, CustomerName, ContactName, Country)
VALUES (NEW.CustomerID, NEW.CustomerName, NEW.ContactName, NEW.Country);
END IF;
END //
CREATE TRIGGER after_customer_delete
AFTER DELETE ON Customers
FOR EACH ROW
BEGIN
DELETE FROM MaterializedActiveCustomers WHERE CustomerID = OLD.CustomerID;
END //
DELIMITER ;
這些觸發器將確保MaterializedActiveCustomers
表隨著Customers
表的變更而保持更新。
雖然 MySQL 支援視圖,但它本身不支援物化視圖。但是,您可以使用具有計劃更新或觸發器的表來實現類似的功能。透過使用這些解決方法,您可以維護可以快速查詢的預先計算的結果,類似於其他資料庫系統中的物化視圖。
連接是 SQL 的基礎,它允許您組合多個表中的資料。除了基本連接之外,高級連接技術還可以處理更複雜的需求。
自連接是一種常規連接,但表與自身連接。它對於比較同一表中的行很有用。
SELECT a.employee_id, a.name, b.name AS manager_name
FROM employees a
INNER JOIN employees b ON a.manager_id = b.employee_id;
LATERAL
連線允許子查詢在FROM
子句中引用前面表格中的欄位。這對於更複雜的查詢很有用。
SELECT a.*, b.*
FROM table1 a
LEFT JOIN LATERAL (
SELECT *
FROM table2 b
WHERE b.column1 = a.column1
ORDER BY b.column2 DESC
LIMIT 1
) b ON TRUE;
處理需要完整外連接但希望避免結果中出現NULL
值的情況。
SELECT COALESCE(a.column1, b.column1) AS column1, a.column2, b.column2
FROM table1 a
FULL OUTER JOIN table2 b ON a.column1 = b.column1;
在連接中應用複雜的條件以更精確地過濾結果。
SELECT a.column1, b.column2
FROM table1 a
INNER JOIN table2 b ON a.column1 = b.column1 AND a.date_column BETWEEN '2023-01-01' AND '2023-12-31';
這些連接分別對於排除和包含查詢很有用。
SELECT a.*
FROM table1 a
LEFT JOIN table2 b ON a.column1 = b.column1
WHERE b.column1 IS NULL;
SELECT a.*
FROM table1 a
WHERE EXISTS (SELECT 1 FROM table2 b WHERE a.column1 = b.column1);
SELECT
語句SELECT
語句可以透過進階功能進行擴展,以滿足複雜的資料檢索要求。
視窗函數對與目前行相關的一組表行執行計算,提供強大的分析功能。
SELECT column1, column2, ROW_NUMBER() OVER (PARTITION BY column1 ORDER BY column2) AS row_num
FROM table_name;
SELECT column1, column2, SUM(column2) OVER (ORDER BY column1) AS running_total
FROM table_name;
SELECT column1, column2, RANK() OVER (PARTITION BY column1 ORDER BY column2) AS rank
FROM table_name;
SELECT column1, column2, AVG(column2) OVER (PARTITION BY column1 ORDER BY column2 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS moving_avg
FROM table_name;
遞歸 CTE 可讓您執行遞歸查詢,這對於分層資料很有用。
WITH RECURSIVE cte AS (
SELECT column1, column2
FROM table_name
WHERE condition
UNION ALL
SELECT t.column1, t.column2
FROM table_name t
INNER JOIN cte ON t.column1 = cte.column1
)
SELECT * FROM cte;
現代 SQL 資料庫通常包含處理 JSON 資料的函數,可讓您儲存和查詢 JSON 文件。
SELECT json_column->>'key' AS value
FROM table_name;
SELECT json_agg(row_to_json(t))
FROM (SELECT column1, column2 FROM table_name) t;
UPDATE table_name
SET json_column = jsonb_set(json_column, '{key}', '"new_value"', true)
WHERE condition;
透視將行轉換為列,提供了一種重新組織和匯總資料以用於報告目的的方法。
SELECT
category,
SUM(CASE WHEN year = 2021 THEN sales ELSE 0 END) AS sales_2021,
SUM(CASE WHEN year = 2022 THEN sales ELSE 0 END) AS sales_2022
FROM sales_data
GROUP BY category;
動態 SQL 允許在執行時間建立和執行 SQL 語句,為需要動態產生的複雜查詢提供靈活性。
EXECUTE 'SELECT * FROM ' || table_name || ' WHERE ' || condition;
PREPARE stmt AS SELECT * FROM table_name WHERE column1 = $1;
EXECUTE stmt('value');
掌握進階 SQL 技術可以讓您最佳化資料庫效能並輕鬆處理複雜查詢。了解執行計劃、利用高階聯結、利用複雜的SELECT
語句、實作進階索引策略是精通 SQL 的關鍵。透過將這些技術整合到您的工作流程中,您可以顯著提高資料庫驅動應用程式的效率和可擴展性。
進階 SQL 技能可讓您處理複雜的資料操作和檢索任務,確保您的應用程式能夠有效率且有效地處理大量資料。無論您是資料庫管理員、開發人員還是資料分析師,這些進階 SQL 技術都將使您能夠充分利用關聯式資料庫,從而獲得更好的效能、更深入的見解和更強大的應用程式。
原文出處:https://dev.to/bilelsalemdev/advanced-sql-mastering-query-optimization-and-complex-joins-4gph