- 使用 WHERE 子句等過濾條件,減少返回結(jié)果集的數(shù)據(jù)量柠偶。
- 盡可能在關(guān)聯(lián)前進行數(shù)據(jù)過濾情妖,減少關(guān)聯(lián)操作。
- 避免使用 SELECT *诱担,只選擇你需要的字段毡证,減少數(shù)據(jù)傳輸量
eg 假設(shè)有一個訂單管理系統(tǒng),需要優(yōu)化以下 SQL 查詢:
SELECT * FROM orders
JOIN customers ON orders.customer_id = customers.id
WHERE orders.order_date > '2022-01-01'
加入訂單表 orders 和客戶表 customers 很可能都包含大量數(shù)據(jù)蔫仙,我們可以首先嘗試在WHERE 子句中加入更多的過濾條件
料睛,例如根據(jù)地區(qū)、訂單狀態(tài)等摇邦,以減少返回結(jié)果集的數(shù)據(jù)量恤煞。
eg 假設(shè)有兩張表,一張是用戶表(User)涎嚼,另一張是訂單表(Order)阱州。用戶表中存儲了用戶的基本信息,訂單表中存儲了用戶的訂單信息法梯,兩張表通過用戶ID進行關(guān)聯(lián)苔货。
當(dāng)需要查詢所有在過去一周內(nèi)下過訂單的活躍用戶信息時,為了減少關(guān)聯(lián)操作
并提高性能立哑,可以先從訂單表中篩選出在過去一周內(nèi)下過訂單的用戶ID夜惭,然后再根據(jù)這些用戶ID去查詢用戶表中的用戶信息
SELECT u.*
FROM User u
WHERE u.user_id IN (
SELECT DISTINCT o.user_id
FROM `Order` o
WHERE o.order_date >= DATE_SUB(NOW(), INTERVAL 1 WEEK)
);
比對操作:避免了直接對兩張表中的數(shù)據(jù)進行比對操作,因為通過子查詢方式铛绰,我們可以先篩選出滿足條件的數(shù)據(jù)再進行查詢诈茧,避免了在關(guān)聯(lián)階段進行大量的比對操作。
- 確保查詢的字段上建立了索引捂掰,并保證索引的有效性敢会。
- 優(yōu)化 SQL 查詢語句中的關(guān)聯(lián)條件曾沈,確保索引被充分利用。
SELECT * FROM orders
JOIN customers ON orders.customer_id = customers.id
WHERE orders.order_date > '2022-01-01'
確保 orders 表中的 order_date 字段和 customers 表中的 id 字段上都建立了索引鸥昏,提高查詢效率
- 避免在
關(guān)聯(lián)
條件中對字段進行函數(shù)處理
原因:索引失效: 當(dāng)在關(guān)聯(lián)條件中對字段進行函數(shù)處理時塞俱,數(shù)據(jù)庫引擎通常無法有效使用索引。因為對字段進行函數(shù)處理后吏垮,原本的字段值發(fā)生了改變障涯,使得無法直接匹配索引中的值,從而導(dǎo)致索引失效膳汪,數(shù)據(jù)庫引擎可能無法有效地利用索引進行高效的數(shù)據(jù)查找唯蝶。
假設(shè)我們有兩個表 orders 和 customers,orders 表存儲訂單信息遗嗽,customers 表存儲客戶信息粘我,我們需要根據(jù)訂單金額和客戶等級進行關(guān)聯(lián)查詢。
首先痹换,讓我們看一下 orders 表的數(shù)據(jù)示例:
| order_id | amount |
|----------|--------|
| 1 | 100.5 |
| 2 | 200.8 |
| 3 | 300.3 |
customers 表的數(shù)據(jù)示例:
| customer_id | level |
|-------------|-------|
| 1 | 101 |
| 2 | 200 |
| 3 | 300 |
原始的 SQL 查詢可能如下涂滴,其中對訂單金額字段進行了舍入處理:
SELECT *
FROM orders o
JOIN customers c ON ROUND(o.amount) = c.level;
為了避免在 JOIN 條件中進行函數(shù)處理,我們可以將數(shù)據(jù)處理提前到查詢前晴音。首先創(chuàng)建帶有舍入后金額的臨時表 tmp_orders:
CREATE TEMPORARY TABLE tmp_orders AS
SELECT order_id, ROUND(amount) AS rounded_amount
FROM orders;
然后基于處理后的數(shù)據(jù)進行關(guān)聯(lián)查詢:
SELECT *
FROM tmp_orders t
JOIN customers c ON t.rounded_amount = c.level;
通過這樣的處理柔纵,我們在查詢前即對訂單金額進行了舍入處理并存儲在臨時表中,避免在關(guān)聯(lián)條件中對字段進行函數(shù)處理锤躁,使得查詢更加簡潔和高效搁料。
- 將復(fù)雜計算的結(jié)果存儲在臨時表中:
原因:1、簡化復(fù)雜邏輯: 復(fù)雜計算的結(jié)果存儲在臨時表中可以將復(fù)雜的邏輯簡化為一個簡單的數(shù)據(jù)訪問操作系羞,使得查詢語句更加清晰和易于維護郭计。
2、減少重復(fù)計算: 復(fù)雜計算通常會消耗較多的計算資源椒振,將計算結(jié)果存儲在臨時表中可以避免重復(fù)進行這些復(fù)雜計算昭伸。在后續(xù)的查詢中,直接訪問臨時表中的結(jié)果澎迎,無需重復(fù)進行耗時的計算庐杨,從而提高了查詢的效率
假設(shè)我們有一個訂單表 orders,需要從中篩選出訂單金額大于一定閾值的訂單夹供,并計算訂單金額超出閾值部分的差值灵份。
首先,讓我們看一下 orders 表的數(shù)據(jù)示例:
| order_id | amount |
|----------|--------|
| 1 | 900 |
| 2 | 1100 |
| 3 | 1200 |
原始的 SQL 查詢可能如下哮洽,計算訂單金額超出閾值部分的差值:
SELECT order_id, amount,
CASE
WHEN amount > 1000 THEN amount - 1000
ELSE 0
END AS excess_amount
FROM orders
WHERE amount > 1000;
為了提高查詢效率填渠,我們可以將計算結(jié)果存儲在臨時表中,并后續(xù)查詢該臨時表。首先創(chuàng)建包含計算結(jié)果的臨時表 tmp_excess_orders:
CREATE TEMPORARY TABLE tmp_excess_orders AS
SELECT order_id, amount,
CASE
WHEN amount > 1000 THEN amount - 1000
ELSE 0
END AS excess_amount
FROM orders
WHERE amount > 1000;
然后可以直接查詢這個臨時表來獲取結(jié)果:
SELECT *
FROM tmp_excess_orders;
- 索引并不是越多越好氛什,索引固然可以提高相應(yīng)的select的效率莺葫,但同時也降低了insert 及 update 的效率
原因:索引建立越多,底層B樹結(jié)構(gòu)每個節(jié)點存儲信息就越多枪眉,插入新數(shù)據(jù)可能需要重新平衡樹結(jié)構(gòu)徙融,這可能涉及移動和重新排序節(jié)點,從而增加了操作的開銷
- 盡量使用數(shù)字型字段瑰谜,若只含數(shù)值信息的字段盡量不要設(shè)計為字符型,這會降低查詢和連接的性能树绩,并會增加存儲開銷萨脑。
原因:
1、查詢性能提升:數(shù)字型字段比字符型字段在查詢時通常具有更好的性能饺饭。數(shù)據(jù)庫引擎可以更快地處理數(shù)字型數(shù)據(jù)的比較渤早、排序和計算操作,相比之下瘫俊,字符型數(shù)據(jù)需要更多的資源和時間來進行相同的操作鹊杖。
2、提高連接性能:在數(shù)據(jù)庫連接操作中扛芽,如果連接字段是數(shù)字型而不是字符型骂蓖,連接操作的效率通常會更高。連接操作需要比較兩個字段的值川尖,并且通過索引來加速連接操作登下;對于數(shù)字型字段,比較和索引查找的效率通常比字符型字段更高叮喳。
可能導(dǎo)致全表掃描的幾種情況:
- 盡量避免使用in和not in被芳,在where子句中使用in和not in,引擎將放棄使用索引而進行全表掃描馍悟。
- 盡量避免使用!=或<>操作符畔濒,在 where語句中使用!=或<>,引擎將放棄使用索引而進行全表掃描锣咒。
- 使用like的時候要注意是否會導(dǎo)致全表掃
慢sql查詢怎么查
- 開啟慢查詢?nèi)罩荆?/li>
在 MySQL 數(shù)據(jù)庫中侵状,您可以通過編輯 MySQL 配置文件 my.cnf
,找到并修改以下選項:
slow_query_log = 1
long_query_time = 1
將 slow_query_log
設(shè)為 1
以開啟慢查詢?nèi)罩居涗洠?code>long_query_time 指定慢查詢的時間閾值毅整,單位為秒壹将。這里設(shè)置為 1
表示超過 1 秒的查詢會被記錄在慢查詢?nèi)罩局小?/p>
- 分析慢查詢?nèi)罩?/li>
定期檢查慢查詢?nèi)罩疚募梢允褂靡韵旅钫业铰樵內(nèi)罩疚募窂剑?/p>
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'slow_query_log_file';
通過查看慢查詢?nèi)罩久担梢哉业綀?zhí)行時間較長的 SQL 查詢語句诽俯。
- 使用數(shù)據(jù)庫性能分析工具
針對慢查詢的 SQL 語句,您可以使用 MySQL 的 EXPLAIN
命令來查看查詢執(zhí)行計劃,例如:
EXPLAIN SELECT * FROM your_table WHERE condition;
這將會顯示查詢執(zhí)行計劃以及可能的性能瓶頸暴区,幫助您理解查詢的執(zhí)行方式和可能的優(yōu)化路徑闯团。
- 優(yōu)化 SQL 查詢
根據(jù)分析結(jié)果,您可以針對性地對慢查詢的 SQL 語句進行優(yōu)化仙粱,例如添加索引房交、重構(gòu)查詢語句、優(yōu)化數(shù)據(jù)庫配置等伐割。
面試題:
統(tǒng)計年齡在 19 到 24 歲之間年齡最大的人數(shù)
SELECT COUNT(*) AS max_age_count
FROM table_name
WHERE age >= 19 AND age <= 24
ORDER BY age DESC
LIMIT 1;
COUNT(*) 候味?
COUNT(*) 是 SQL 中用于統(tǒng)計符合特定條件的行數(shù)的聚合函數(shù)。它可以用來統(tǒng)計表中滿足條件的記錄的數(shù)量隔心。
例如白群,如果您有一個名為 "students" 的表,其中包含了學(xué)生的信息硬霍,您可以使用 COUNT(*) 來統(tǒng)計表中的記錄數(shù)量帜慢,如下所示:
SELECT COUNT(*) AS total_students
FROM students;
這將返回一個名為 "total_students" 的結(jié)果集,其中包含了表中記錄的總數(shù)唯卖。
您也可以使用 COUNT(*) 結(jié)合 WHERE 子句來統(tǒng)計滿足特定條件的記錄數(shù)量粱玲,例如:
SELECT COUNT(*) AS passed_students
FROM students
WHERE score >= 60;
這將返回一個名為 "passed_students" 的結(jié)果集,其中包含了分?jǐn)?shù)大于等于 60 分的學(xué)生的記錄數(shù)量拜轨。
總之抽减,COUNT(*) 是 SQL 中非常常用的聚合函數(shù),用于統(tǒng)計行數(shù)橄碾,可以幫助您快速獲取所需信息的數(shù)量統(tǒng)計胯甩。