『壹』 美團面試題:慢sql有遇到過嗎是怎麼解決的
大家好,我是田維常,可以叫我老田,也可以叫我田哥
。2017年的時候,我剛去上海,朋友內悄指早推我去美團面試,之前我也寫過一個一篇文章,也是在美團面試中遇到的:
美團面試題:String s = new String("111")會創建幾個對象?
關於慢SQL,我和面試官扯了很久,面試官也是很謙虛的,總是點頭,自己以為回答的還可以。最後的最後,還是說了「 你先回去等通知吧! 」。
所以,我決定把這個慢SQL技術點,好好和你分享分享。希望你下次在遇到類似的面試,能順順利利輕輕鬆鬆的斬獲自己想要的offer。
MySQL的慢查詢日誌是MySQL提供的一種日誌記錄,它用來記錄MySQL中查詢時間超過(大於)設置閾值(long_query_time)的語句,記錄到慢查詢日誌中。
其中,long_query_time的默認值是10,單位是秒,也就是說默認情況下,你的SQL查詢時間超過10秒就算慢SQL了。
在MySQL中,慢SQL日誌默認是未開啟的,也就說就算出現了慢SQL,也不會告訴你的,如果需要知道哪些SQL是慢SQL,需要我們手動開啟慢SQL日誌的。
關於慢SQL是否開啟,我們可以通過下面這個命令來查看:
在這里插入圖片描述
通過命令,我們就可以看到slow_query_log項為OFF,說明我們的慢SQL日誌並未開啟。另外我們也可以看到我們慢SQL日誌存放於哪個目錄下和日誌文件名。
下面我們來開啟慢SQL日誌,執行下面的命令:
這里需要注意,這里開啟的是我們當前的資料庫,並且,我們重啟資料庫後會失效的。
開啟慢SQL日誌後,再次查看:
slow_query_log項已經變成ON,說明開啟成功。
上面說過慢SQL默認時間是10秒,我們通過下面的命令就可以看到我們慢SQL的默認時間:
在這里插入圖片描述
我們總不能一直使用這個默認值,可能很多業務需要時間更短或更長,所以此時,我們就需要對默認時間進行修改,修改命令如下:
修改完了,我們再來看看是否已經改成了3秒。
這里需要注意:想要永久的生效,還需要修改MySQL下面的配置文件my.cnf 文件。
注意:不同操作系統,配置有些區別。
Linux操作系統中
Windows操作系統中
執行一條慢SQL,因為我們前面已經設置好了慢SQL時間為3秒,所以,我們只要執行一條SQL時間超過3秒即可。
該SQL耗時4.024秒,下面我們就來查看慢SQL出現了多少條。
使用命令:
找到慢SQL日誌文件,打開後就會出現類似下面這樣的語句;
簡單說明:
切記
通常我們定位慢SQL有兩種方式:
第一種:定位慢查詢 SQL 可以通過兩個表象進行判斷
第二種:根據不同的資料庫使用不同的方式獲取問題 SQL
如果開啟了慢SQL日誌後,可能會有大量的慢SQL日誌產生,此時再用肉眼看,那是不太現實的,所以大佬們就給我搞了個工具: mysqlmpslow 。
mysqlmpslow 能將相同的慢SQL歸類,並統計出相同的SQL執行的次數,每次執行耗時多久、總耗時,每次返回的行數、總行數,以及客戶端連接信息等。
通過命令
可以看到相關參數的說明:
比較常用的參數有這么幾個:
mysqlmpslow 常用的使用逗慶方式如下:
如上一條命令,應該是mysqlmpslow最簡單的一種形式,其中-s參數是以什麼方式排序的意思,c指代的是以總數從大到小的方式排序。-s的常用子參數有:c: 相同查詢以查詢條數和從大到小排序。t: 以查詢總時間的方式從大到小排序。l: 以查詢鎖的總時間的方式從大到小排序。at: 以查詢平均時間的方式從大到小排序。al: 以查詢鎖平均時間的方式從大到啟雀小排序。
同樣的,還可以增加其他參數,實際使用的時候,按照自己的情況來。
其他常用方式:
接下,我們來個實際操作。
這其中的 SQL 語句因為涉及某些信息,所以我都用*號將主體替換了,如果希望得到具體的值,使用-a參數。
使用 mysqlmpslow 查詢出來的摘要信息,包含了這些內容:
Count : 464 :表示慢查詢日誌總共記錄到這條sql語句執行的次數;
Time=18.35s (8515s) :18.35s表示平均執行時間(-s at),8515s表示總的執行時間(-s t);
Lock=0.01s (3s) :與上面的Time相同,第一個表示平均鎖定時間(-s al),括弧內的表示總的鎖定時間(-s l)(也有另一種說法,說是表示的等待鎖釋放的時間);
Rows=90884.0 (42170176) : 第一個值表示掃描的平均行數(-s ar),括弧內的值表示掃描的總行數(-s r)。
是不是
so easy!!!!
『貳』 經典sql面試題及答案第10期
create proc 存儲過程名
[@參數名 參數類型[, @參數名 參數類型...]]
as
批處理語句
go
alter proc 存儲過程名
[@參數名 參數類型[, @參數名 參數類型...]]
as
批處理語句
go
drop proc 存儲過程名
exec proc 存儲過程名 [參數值[, 參數值...]]
不一樣,加括弧是執行sql語句,不加括弧是執行存儲過程。
a. 以Return傳回整數
b. 以output格式傳回參數
c. Recordset
返回值的區別: output和return都可在批次程式中用變數接收,而recordset則傳回到執行批次的客戶端中。
create proc queryPage
@tablename nvarchar(50), --用於傳入表名
@idname nvarchar(50), --用於傳入欄位名
@pagesize int, --用於傳入每頁記錄數
@currentpage int, --用於傳入希望查看的頁面編號
@totalpages int output --用於傳出頁面總數
as
--聲明保存查遲友詢語句的局部變數:
declare @sql as nvarchar(1000)
--聲明保存記錄總碼盯槐數的局部變數:
declare @rowcount as int
--獲得記錄總數:
set @sql='select @rc=count() from '+@tablename --不要直接執行select @rowcount=count() from @tablename
--將參數傳入語句:
exec sp_executesql @sql,N'@rc int output',@rc=@rowcount output
--將根據每頁的行數得到則拿的總頁數保存到輸出參數中:
set @totalpages = ceiling(cast(@rowcount as float)/cast(@pagesize as float))
if @currentpage >1
begin if @currentpage>@totalpages
begin set @currentpage = @totalpages --則顯示最後一頁
end
set @sql = 'select top '+cast(@pagesize as varchar) +' * from '+@tablename+' where '+@idname+' not in (select top ' +cast(@pagesize*(@currentpage-1) as varchar) +' '+@idname+' from '+@tablename+' order by '+@idname+') order by '+@idname
end else --只選第一頁就不必使用子查詢了,提高性能
begin set @sql = 'select top '+cast(@pagesize as varchar) +' * from '+@tablename+' order by '+@idname
end exec(@sql) --執行查詢語句
go
『叄』 經典教師 學生 成績sql面試題再次來襲2(附答案)
點擊鏈接加入QQ群229390571(免費公開課、視頻應有盡有): https://jq.qq.com/?_wv=1027&k=5rbudQa
概述
續一下之前講的sql練習方面內容,怕有行悔些朋友找不到數據,所以這里把建表和准備數據部分也放枯孫著。
建表語句
CREATE TABLE students
(sno VARCHAR(3) NOT NULL,
sname VARCHAR(4) NOT NULL,
ssex VARCHAR(2) NOT NULL,
sbirthday DATETIME,
class VARCHAR(5))
CREATE TABLE courses
(cno VARCHAR(5) NOT NULL,
cname VARCHAR(10) NOT NULL,
tno VARCHAR(10) NOT NULL)
CREATE TABLE scores
(sno VARCHAR(3) NOT NULL,
cno VARCHAR(5) NOT NULL,
degree NUMERIC(10, 1) NOT NULL)
CREATE TABLE teachers
(tno VARCHAR(3) NOT NULL,
tname VARCHAR(4) NOT NULL, tsex VARCHAR(2) NOT NULL,
tbirthday DATETIME NOT NULL, prof VARCHAR(6),
depart VARCHAR(10) NOT NULL)
插入數據
INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (108 ,'曾華' ,'男' ,'1977-09-01',95033);
INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (105 ,'匡明' ,'男' ,'1975-10-02',95031);
INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (107 ,'王麗' ,'女' ,'1976-01-23',95033);
INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (101 ,'李軍' ,'男' ,'1976-02-20',95033);
INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (109 ,'王芳' ,'女' ,'1975-02-10',95031);
INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (103 ,'陸君' ,'男' ,'1974-06-03',95031);
INSERT INTO COURSES(CNO,CNAME,TNO)VALUES ('3-105'沒帶鏈 ,'計算機導論',825);
INSERT INTO COURSES(CNO,CNAME,TNO)VALUES ('3-245' ,'操作系統' ,804);
INSERT INTO COURSES(CNO,CNAME,TNO)VALUES ('6-166' ,'數據電路' ,856);
INSERT INTO COURSES(CNO,CNAME,TNO)VALUES ('9-888' ,'高等數學' ,100);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (103,'3-245',86);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (105,'3-245',75);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (109,'3-245',68);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (103,'3-105',92);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (105,'3-105',88);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (109,'3-105',76);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (101,'3-105',64);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (107,'3-105',91);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (108,'3-105',78);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (101,'6-166',85);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (107,'6-106',79);
INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (108,'6-166',81);
INSERT INTO TEACHERS(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART) VALUES (804,'李誠','男','1958-12-02','副教授','計算機系');
INSERT INTO TEACHERS(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART) VALUES (856,'張旭','男','1969-03-12','講師','電子工程系');
INSERT INTO TEACHERS(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART) VALUES (825,'王萍','女','1972-05-05','助教','計算機系');
INSERT INTO TEACHERS(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART) VALUES (831,'劉冰','女','1977-08-14','助教','電子工程系');
題目(先思考如何實現)
1、查詢所有學生的Sname、Cname和Degree列。
2、查詢「95033」班所選課程的平均分。
3、假設使用如下命令建立了一個grade表:
create table grade(low number(3,0),upp number(3),rank char(1));
insert into grade values(90,100,』A』);
insert into grade values(80,89,』B』);
insert into grade values(70,79,』C』);
insert into grade values(60,69,』D』);
insert into grade values(0,59,』E』);
commit;
現查詢所有同學的Sno、Cno和rank列。
4、查詢選修「3-105」課程的成績高於「109」號同學成績的所有同學的記錄。
5、查詢score中選學一門以上課程的同學中分數為非最高分成績的記錄。
6、查詢成績高於學號為「109」、課程號為「3-105」的成績的所有記錄。
7、查詢和學號為108的同學同年出生的所有學生的Sno、Sname和Sbirthday列。
8、查詢「張旭「教師任課的學生成績。
9、查詢選修某課程的同學人數多於5人的教師姓名。
10、查詢95033班和95031班全體學生的記錄。
11、查詢存在有85分以上成績的課程Cno.
12、查詢出「計算機系「教師所教課程的成績表。
13、查詢「計算機系」與「電子工程系「不同職稱的教師的Tname和Prof。
14、查詢選修編號為「3-105「課程且成績至少高於選修編號為「3-245」的同學的Cno、Sno和Degree,並按Degree從高到低次序排序。
15、查詢選修編號為「3-105」且成績高於選修編號為「3-245」課程的同學的Cno、Sno和Degree.
答案
1.查詢所有學生的Sname、Cname和Degree列。
SELECT Sname,Cname,Degree
FROM Students INNER JOIN Scores
ON(Students.Sno=Scores.Sno) INNER JOIN Courses
ON(Scores.Cno=Courses.Cno)
ORDER BY Sname;
2.查詢「95033」班所選課程的平均分。
SELECT Cname,AVG(Degree)
FROM Students INNER JOIN Scores
ON(Students.Sno=Scores.Sno) INNER JOIN Courses
ON(Scores.Cno=Courses.Cno)
WHERE Class='95033'
GROUP BY Courses.Cno
ORDER BY Cname;
3.假設使用如下命令建立了一個grade表:
CREATE TABLE grade(low TINYINT,upp TINYINT,rank CHAR(1));
INSERT INTO grade VALUES(90,100,'A');
INSERT INTO grade VALUES(80,89,'B');
INSERT INTO grade VALUES(70,79,'C');
INSERT INTO grade VALUES(60,69,'D');
INSERT INTO grade VALUES(0,59,'E');
現查詢所有同學的Sno、Cno和rank列。
SELECT Sno,Cno,rank
FROM Scores INNER JOIN grade
ON(Scores.Degree>=grade.low AND Scores.Degree<=grade.upp)
ORDER BY Sno;
4.查詢選修「3-105」課程的成績高於「109」號同學成績的所有同學的記錄。
SELECT s1.Sno,s1.Degree
FROM Scores AS s1 INNER JOIN Scores AS s2
ON(s1.Cno=s2.Cno AND s1.Degree>s2.Degree)
WHERE s1.Cno='3-105' AND s2.Sno='109'
ORDER BY s1.Sno;
5.查詢score中選學一門以上課程的同學中分數為非最高分成績的記錄。
SELECT *
FROM Scores
GROUP BY Sno
HAVING COUNT(cno)>1 AND Degree!=MAX(Degree);
6.查詢成績高於學號為「109」、課程號為「3-105」的成績的所有記錄。
SELECT s1.Sno,s1.Degree
FROM Scores AS s1 INNER JOIN Scores AS s2
ON(s1.Cno=s2.Cno AND s1.Degree>s2.Degree)
WHERE s1.Cno='3-105' AND s2.Sno='109'
ORDER BY s1.Sno;
7.查詢和學號為108的同學同年出生的所有學生的Sno、Sname和Sbirthday列。
SELECT s1.Sno,s1.Sname,s1.Sbirthday
FROM Students AS s1 INNER JOIN Students AS s2
ON(YEAR(s1.Sbirthday)=YEAR(s2.Sbirthday))
WHERE s2.Sno='108';
8.查詢「張旭「教師任課的學生成績。
SELECT Sno,Degree
FROM Scores INNER JOIN Courses
ON(Scores.Cno=Courses.Cno) INNER JOIN Teachers
ON(Courses.Tno=Teachers.Tno)
WHERE Teachers.Tname='張旭';
9.查詢選修某課程的同學人數多於5人的教師姓名。
SELECT DISTINCT Tname
FROM Scores INNER JOIN Courses
ON(Scores.Cno=Courses.Cno) INNER JOIN Teachers
ON(Courses.Tno=Teachers.Tno)
WHERE Courses.Cno IN(SELECT Cno FROM Scores GROUP BY(Cno) HAVING COUNT(Sno)>5);
10.查詢95033班和95031班全體學生的記錄。
SELECT *
FROM Students
WHERE Class IN ('95033','95031')
ORDER BY Class;
11.查詢存在有85分以上成績的課程Cno.
SELECT DISTINCT Cno FROM Scores WHERE Degree>85;
12.查詢出「計算機系「教師所教課程的成績表。
SELECT Tname,Cname,SName,Degree
FROM Teachers INNER JOIN Courses
ON(Teachers.Tno=Courses.Tno) INNER JOIN Scores
ON(Courses.Cno=Scores.Cno) INNER JOIN Students
ON(Scores.Sno=Students.Sno)
WHERE Teachers.Depart='計算機系'
ORDER BY Tname,Cname,Degree DESC;
13.查詢「計算機系」與「電子工程系「不同職稱的教師的Tname和Prof。
SELECT Tname,Prof
FROM Teachers
WHERE Depart='計算機系' AND Prof NOT IN(
SELECT DISTINCT Prof
FROM Teachers
WHERE Depart='電子工程系');
14.查詢選修編號為「3-105「課程且成績至少高於任意選修編號為「3-245」的同學的成績的Cno、Sno和Degree,並按Degree從高到低次序排序。
SELECT Cno,Sno,Degree
FROM Scores
WHERE Cno='3-105' AND Degree > ANY(
SELECT Degree
FROM Scores
WHERE Cno='3-245')
ORDER BY Degree DESC;
15.查詢選修編號為「3-105」且成績高於所有選修編號為「3-245」課程的同學的Cno、Sno和Degree.
SELECT Cno,Sno,Degree
FROM Scores
WHERE Cno='3-105' AND Degree > ALL(
SELECT Degree
FROM Scores
WHERE Cno='3-245')
ORDER BY Degree DESC;
以上僅為參考答案
『肆』 關於Oracle PL/SQL優化,一面試題,求助
應該是說結構不是固定的,可能資料庫存在1000個表,每個需求不同,因此不能定義臨時表來存個儲這樣。記得不太清楚了,應該是靠怎樣避免重復創建表吧。
就算結構是靈活的,也可以定義臨時表,多定義幾個就是。
『伍』 面試題_說說你是怎麼資料庫優化的
對sql語句優化:
就是能分開寫的語句就分開寫,不要一次性就解決,這樣對效率來說是很大的開銷的
避免使用不兼容伍臘的數據類型:
如float和int,char和varchar等都是不兼容的。
盡量避免在where子句中對欄位進行函孫橘物數或表達式操作
避免使用isnotnull、in等一些無法讓系統使用索引操作的詞
合理使用exists,notexists字句
盡量則液避免在索引過的字元數據中,使用非打頭字母所有
避免困難的正規表達式
對mysql優化:
1.選取最適用的欄位屬性,可以的情況下,應該盡量把欄位設置為NOTNULL
2.使用連接(JOIN)來代替子查詢
3.使用聯合來代替手動創建的臨時表
4.增刪改或者多條查詢數據時使用事務操作
5.鎖定表(代替事務的另一種方法)
6.使用外鍵(鎖定表的方法可以維護數據的完整性,但它不能保證數據的關聯性,應該使用外鍵)
7.可以優化SQL查詢演算法,提高查詢速度8.給數據量大的查詢次數頻繁而修改次數少的數據表添加索引,提升查詢速度
面試題_說說你是怎麼資料庫優化的
標簽:鎖定oat試題數據表arc手動頻繁添加設置
『陸』 這些SQL優化技巧握在手,面試可以橫著走……
一、SQL執行順序
二、基礎SQL優化
1、查詢SQL盡量不要使用select *,而是具體欄位
1)反例
2)正例
3)理由
2、避免在where子句中使用or來連接條件
查詢id為1或者薪水為3000的用戶:
1)反例
2)正例
使用union all:
分開兩條SQL寫:
3)理由
3、使用varchar代替char
1)反例
2)正例
3)理由
4、盡量使用數值替代字元串類型
5、查詢盡量避免返回大量數據
如果查詢返回數據量很大,就會造成查詢時間過長,網路傳輸時間過長。同時,大量數據返回也可能沒有實際意義。如返回上千條甚至更多,用戶也看不過來。
通常採用分頁,一頁習慣10/20/50/100條。
6、使用explain分析你SQL執行計劃
SQL很靈活,一個需求可以很多實現,那哪個最優呢?SQL提供了explain關鍵字,它可以分析你的SQL執行計劃,看它是否最佳。Explain主要看SQL是否使用了索引。
返回結果:
7、是否使用了索引及其掃描類型
type:
性能排行:
System > const > eq_ref > ref > range > index > ALL
possible_keys:
key:
8、創建name欄位的索引
提高查詢速度的最簡單最佳的方式。
9、優化like語句
模糊查詢,程序員最喜歡的就是使用like,但是like很可能讓你的索引失效。
1)反例
2)正例
3)理由
未使用索引,故意使用sex非索引欄位:
主鍵索引生效:
索引失效,type=ALL,全表掃描:
10、字元串怪現象
1)反例
2)正例
3)理由
為什麼第一條語句未加單引號就不走索引了呢?這是因為不加單引號時,是字元串跟數字的比較,它們類型不匹配,MySQL會做隱式的類型轉換,把它們轉換為數值類型再做比較。
11、索引不宜太多,一般5個以內
12、索引不適合建在有大量重復數據的欄位上
如性別欄位。因為SQL優化器是根據表中數據量來進行查詢優化的,如果索引列有大量重復數據,Mysql查詢優化器推算發現不走索引的成本更低,很可能就放棄索引了。
13、where限定查詢的數據
數據中假定就一個男的記錄。
1)反例
2)正例
3)理由
14、避免在索引列上使用內置函數
業務需求:查詢最近七天內新生兒(用學生表替代下)
給birthday欄位創建索引:
當前時間加7天:
1)反例
2)正例
3)理由
15、避免在where中對欄位進行表達式操作
1)反例
2)正例
3)理由
16、避免在where子句中使用!=或>操作符
應盡量避免在where子句中使用!=或>操作符,否則引擎將放棄使用索引而進行全表掃描。記住實現業務優先,實在沒辦法,就只能使用,並不是不能使用。如果不能使用,SQL也就無需支持了。
1)反例
2)理由
17、去重distinct過濾欄位要少
1)理由
18、where中使用默認值代替null
環境准備:
1)反例
2)正例
3)理由
三、高級SQL優化
1、批量插入性能提升
大量數據提交,上千,上萬,批量性能非常快,mysql獨有。
1)多條提交
2)批量提交
3)理由
2、批量刪除優化
避免同時修改或刪除過多數據,因為會造成cpu利用率過高,會造成鎖表操作,從而影響別人對資料庫的訪問。
1)反例
2)正例
3)理由
3、偽刪除設計
1)商品狀態(state)
2)理由
4、提高group by語句的效率
可以在執行到該語句前,把不需要的記錄過濾掉。
1)反例:先分組,再過濾
2)正例:先過濾,後分組
5、復合索引最左特性
創建復合索引,也就是多個欄位。
滿足復合索引的左側順序,哪怕只是部分,復合索引生效。
沒有出現左邊的欄位,則不滿足最左特性,索引失效。
復合索引全使用,按左側順序出現 name,salary,索引生效。
雖然違背了最左特性,但MYSQL執行SQL時會進行優化,底層進行顛倒優化。
1)理由
6、排序欄位創建索引
什麼樣的欄位才需要創建索引呢?原則就是where和order by中常出現的欄位就創建索引。
7、刪除冗餘和重復的索引
8、不要有超過5個以上的表連接
9、inner join 、left join、right join,優先使用inner join
三種連接如果結果相同,優先使用inner join,如果使用left join左邊表盡量小。
1)理由
10、in子查詢的優化
日常開發實現業務需求可以有兩種方式實現:
如需求:查詢所有部門的所有員工:
假設表A表示某企業的員工表,表B表示部門表,查詢所有部門的所有員工,很容易有以下程序實現,可以抽象成這樣的一個嵌套循環:
『柒』 搞定這30個SQL面試問題,助你成功升級面霸
CREATE VIEW view_name AS
SELECT column_name1, column_name2
FROM table_name
WHERE CONDITION;
我們一起分享AI學習與發展的干貨
歡迎豎局關注全平台AI垂類余液讓自媒體 「讀埋悶芯術」
『捌』 SQL優化萬能公式:5 大步驟 + 10 個案例
在應用開發的早期,數據量少,開發人員開發功能時更重視功能上的實現,隨著生產數據的增長,很多SQL語句開始暴露出性能問題,對生產的影響也越來越大,有時可能這些有問題的SQL就是整個系統性能的瓶頸。
1、通過慢查日誌等定位那些執行效率較低的SQL語句
2、explain 分析SQL的執行計劃
type由上至下,效率越來越高
Extra
3、show profile 分析
了解SQL執行的線程的狀態及消耗的時間。默認是關閉的,開啟語句「set profiling = 1;」
4、trace
trace分析優化器如何選擇執行計劃,通過trace文件能夠進一步了解為什麼優惠券選擇A執行計劃而不選擇B執行計劃。
5、確定問題並採用相應的措施
案例1、最左匹配
索引
SQL語句
查詢匹配從左往右匹配,要使用order_no走索引,必須查詢條件攜帶shop_id或者索引( shop_id , order_no )調換前後順序
案例2、隱式轉換
索引
SQL語句
隱式轉換相當於在索引上做運算,會讓索引失效。mobile是字元類型,使用了數字,應該使用字元串匹配,否則MySQL會用到隱式替換,導致索引失效。
案例3、大分頁
索引
SQL語句
對於大分頁的場景,可以優先讓產品優化需求,如果沒有優化的,有如下兩種優化方式, 一種是把上一次的最後一條數據,也即上面的c傳過來,然後做「c < xxx」處理,但是這種一般需要改介面協議,並不一定可行。另一種是採用延遲關聯的方式進行處理,減少SQL回表,但是要記得索引需要完全覆蓋才有效果,SQL改動如下
案例4、in + order by
索引
SQL語句
in查詢在MySQL底層是通過n*m的方式去搜索,類似union,但是效率比union高。in查詢在進行cost代價計算時(代價 = 元組數 * IO平均值),是通過將in包含的數值,一條條去查詢獲取元組數的,因此這個計算過程會比較的慢,所以MySQL設置了個臨界值(eq_range_index_pe_limit),5.6之後超過這個臨界值後該列的cost就不參與計算了。因此會導致執行計劃選擇不準確。默認是200,即in條件超過了200個數據,會導致in的代價計算存在問題,可能會導致Mysql選擇的索引不準確。
處理方式,可以( order_status , created_at )互換前後順序,並且調整SQL為延遲關聯。
案例5、范圍查詢阻斷,後續欄位不能走索引
索引
SQL語句
范圍查詢還有「IN、between」
案例6、不等於、不包含不能用到索引的快速搜索。(可以用到ICP)
在索引上,避免使用NOT、!=、>、!、NOT EXISTS、NOT IN、NOT LIKE等
案例7、優化器選擇不使用索引的情況
如果要求訪問的數據量很小,則優化器還是會選擇輔助索引,但是當訪問的數據占整個表中數據的蠻大一部分時(一般是20%左右),優化器會選擇通過聚集索引來查找數據。
查詢出所有未支付的訂單,一般這種訂單是很少的,即使建了索引,也沒法使用索引。
案例8、復雜查詢
如果是統計某些數據,可能改用數倉進行解決;如果是業務上就有那麼復雜的查詢,可能就不建議繼續走SQL了,而是採用其他的方式進行解決,比如使用ES等進行解決。
案例9、asc和desc混用
desc 和asc混用時會導致索引失效
案例10、大數據
對於推送業務的數據存儲,可能數據量會很大,如果在方案的選擇上,最終選擇存儲在MySQL上,並且做7天等有效期的保存。那麼需要注意,頻繁的清理數據,會照成數據碎片,需要聯系DBA進行數據碎片處理。
『玖』 幾個面試中遇到的SQL題,大家幫幫忙
1,select * from pages where url='..' union all
select * from pages where title='...' union all
select * from pages where body='...'
2,select case when a>b then a when b<=c then c else b end from 表
3,A表建觸發器
CREATE TRIGGER myt
ON 表A
FOR UPDATE
AS
If UPDATE(主鍵)
BEGIN
update b
set 同欄位1=a.同欄位1,同欄位2=a.同欄位2
from 表B b,inserted a
where b.主鍵=a.主鍵
END
『拾』 sql優化的幾種方法面試
1.你把學校裡面學的東西都弄通,弄懂就可以了,基本的概念和原理都能說出來,如你說的sql優化就是:為資料庫建立索引,如何提高檢索速度之類的問題。教科書上都有說啊。
2.面試不是說一定要什麼都懂才能去面的,你要找多一點面試經驗,面試經常問什麼問題,比如指針,鏈表等,有針對性地准備一下,不用全部一骨碌地看。
3.積累經驗和編程作品,多做項目,自己多寫些程序。面試就有了籌碼。