面試中我們經常會被要求做一份筆試題,筆試題通過後會有技術大佬來面試我們。在筆試題最後一般都是有一道關於mysql語句的問題,讓手寫出增、刪、改、查語句,今天我們就學習一下mysql語句。
數據表連接問題,左外連接、右外連接、內連接等
一、交叉連接(CROSS JOIN)
交叉連接(CROSS JOIN):有兩種,顯式的和隱式的,不帶ON子句,返回的是兩表的乘積,也叫笛卡爾積。
例如:下面的語句1和語句2的結果是相同的。
語句1:隱式的交叉連接,沒有CROSS JOIN。
語句2:顯式的交叉連接,使用CROSS JOIN。
語句1和語句2的結果是相同的,查詢結果如下:
二、內連接(INNER JOIN)
內連接(INNER JOIN):有兩種,顯式的和隱式的,返回連接表中符合連接條件和查詢條件的數據行。(所謂的連結表就是資料庫在做查詢形成的中間表)。
例如:下面的語句3和語句4的結果是相同的。
語句3:隱式的內連接,沒有INNER JOIN,形成的中間表為兩個表的笛卡爾積。
語句4:顯示的內連接,一般稱為內連接,有INNER JOIN,形成的中間表為兩個表經過ON條件過濾後的笛卡爾積。
語句3和語句4的查詢結果:
三、外連接(OUTER JOIN):外連不但返回符合連接和查詢條件的數據行,還返回不符合條件的一些行。外連接分三類:左外連接(LEFT OUTER JOIN)、右外連接(RIGHT OUTER JOIN)和全外連接(FULL OUTER JOIN)。
三者的共同點是都返回符合連接條件和查詢條件(即:內連接)的數據行。不同點如下:
左外連接還返回左表中不符合連接條件單符合查詢條件的數據行。
右外連接還返回右表中不符合連接條件單符合查詢條件的數據行。
全外連接還返回左表中不符合連接條件單符合查詢條件的數據行,並且還返回右表中不符合連接條件單符合查詢條件的數據行。全外連接實際是上左外連接和右外連接的數學合集(去掉重複),即「全外=左外 UNION 右外」。
說明:左表就是在「(LEFT OUTER JOIN)」關鍵字左邊的表。右表當然就是右邊的了。在三種類型的外連接中,OUTER 關鍵字是可省略的。
下面舉例說明:
語句5:左外連接(LEFT OUTER JOIN)
語句6:右外連接(RIGHT OUTER JOIN)
注意:WHERE條件放在ON後面查詢的結果是不一樣的。例如:
語句7:WHERE條件獨立。
語句8:將語句7中的WHERE條件放到ON後面。
從語句7和語句8查詢的結果來看,顯然是不相同的,語句8顯示的結果是難以理解的。因此,推薦在寫連接查詢的時候,ON後面只跟連接條件,而對中間表限制的條件都寫到WHERE子句中。
語句9:全外連接(FULL OUTER JOIN)。
注意:MySQL是不支持全外的連接的,這裡給出的寫法適合Oracle和DB2。但是可以通過左外和右外求合集來獲取全外連接的查詢結果。下圖是上面SQL在Oracle下執行的結果:
語句10:左外和右外的合集,實際上查詢結果和語句9是相同的。
語句9和語句10的查詢結果是相同的,如下:
四、聯合連接(UNION JOIN):這是一種很少見的連接方式。Oracle、MySQL均不支持,其作用是:找出全外連接和內連接之間差異的所有行。這在數據分析中排錯中比較常用。也可以利用資料庫的集合操作來實現此功能。
語句11:聯合查詢(UNION JOIN)例句,還沒有找到能執行的SQL環境。
語句12:語句11在DB2下的等價實現。還不知道DB2是否支持語句11呢!
語句13:語句11在Oracle下的等價實現。
五、自然連接(NATURAL INNER JOIN):說真的,這種連接查詢沒有存在的價值,既然是SQL2標準中定義的,就給出個例子看看吧。自然連接無需指定連接列,SQL會檢查兩個表中是否相同名稱的列,且假設他們在連接條件中使用,並且在連接條件中僅包含一個連接列。不允許使用ON語句,不允許指定顯示列,顯示列只能用*表示(ORACLE環境下測試的)。對於每種連接類型(除了交叉連接外),均可指定NATURAL。下面給出幾個例子。
語句14:
語句15:
語句16:
語句17:
六、SQL查詢的基本原理:兩種情況介紹。
第一、 單表查詢:根據WHERE條件過濾表中的記錄,形成中間表(這個中間表對用戶是不可見的);然後根據SELECT的選擇列選擇相應的列進行返回最終結果。
第二、 兩表連接查詢:對兩表求積(笛卡爾積)並用ON條件和連接連接類型進行過濾形成中間表;然後根據WHERE條件過濾中間表的記錄,並根據SELECT指定的列返回查詢結果。
第三、 多表連接查詢:先對第一個和第二個表按照兩表連接做查詢,然後用查詢結果和第三個表做連接查詢,以此類推,直到所有的表都連接上為止,最終形成一個中間的結果表,然後根據WHERE條件過濾中間表的記錄,並根據SELECT指定的列返回查詢結果。
理解SQL查詢的過程是進行SQL優化的理論依據。
七、ON後面的條件(ON條件)和WHERE條件的區別:
ON條件:是過濾兩個連結表笛卡爾積形成中間表的約束條件。
WHERE條件:在有ON條件的SELECT語句中是過濾中間表的約束條件。在沒有ON的單表查詢中,是限制物理表或者中間查詢結果返回記錄的約束。在兩表或多表連接中是限制連接形成最終中間表的返回結果的約束。
從這裡可以看出,將WHERE條件移入ON後面是不恰當的。推薦的做法是:
ON只進行連接操作,WHERE只過濾中間表的記錄。
八、總結
連接查詢是SQL查詢的核心,連接查詢的連接類型選擇依據實際需求。如果選擇不當,非但不能提高查詢效率,反而會帶來一些邏輯錯誤或者性能低下。下面總結一下兩表連接查詢選擇方式的依據:
1、 查兩表關聯列相等的數據用內連接。
2、 Col_L是Col_R的子集時用右外連接。
3、 Col_R是Col_L的子集時用左外連接。
4、 Col_R和Col_L彼此有交集但彼此互不為子集時候用全外。
5、 求差操作的時候用聯合查詢。
多個表查詢的時候,這些不同的連接類型可以寫到一塊。例如:
上面這個SQL查詢是多表連接的一個示範。
同上
sql語句優化
1.查詢的模糊匹配
儘量避免在一個複雜查詢裡面使用 LIKE '%parm1%'—— 紅色標識位置的百分號會導致相關列的索引無法使用,最好不要用。
解決辦法:
其實只需要對該腳本略做改進,查詢速度便會提高近百倍。改進方法如下:
a、修改前臺程序——把查詢條件的供應商名稱一欄由原來的文本輸入改為下拉列表,用戶模糊輸入供應商名稱時,直接在前臺就幫忙定位到具體的供應商,這樣在調用後臺程序時,這列就可以直接用等於來關聯了。
b、直接修改後臺——根據輸入條件,先查出符合條件的供應商,並把相關記錄保存在一個臨時表裡頭,然後再用臨時表去做複雜關聯。
2.索引問題
在做性能跟蹤分析過程中,經常發現有不少後臺程序的性能問題是因為缺少合適索引造成的,有些表甚至一個索引都沒有。這種情況往往都是因為在設計表時,沒去定義索引,而開發初期,由於表記錄很少,索引創建與否,可能對性能沒啥影響,開發人員因此也未多加重視。然一旦程序發布到生產環境,隨著時間的推移,表記錄越來越多。這時缺少索引,對性能的影響便會越來越大了。
法則:不要在建立的索引的數據列上進行下列操作:
避免對索引欄位進行計算操作
避免在索引欄位上使用not,<>,!=
避免在索引列上使用IS NULL和IS NOT NULL
避免在索引列上出現數據類型轉換
避免在索引欄位上使用函數
避免建立索引的列中使用空值
3.複雜操作
部分UPDATE、SELECT 語句 寫得很複雜(經常嵌套多級子查詢)——可以考慮適當拆成幾步,先生成一些臨時數據表,再進行關聯操作。
4.update
同一個表的修改在一個過程裡出現好幾十次,如:
這類腳本其實可以很簡單就整合在一個UPDATE語句來完成(前些時候在協助xxx項目做性能問題分析時就發現存在這種情況)
5.在可以使用UNION ALL的語句裡,使用了UNION
UNION 因為會將各查詢子集的記錄做比較,故比起UNION ALL ,通常速度都會慢上許多。一般來說,如果使用UNION ALL能滿足要求的話,務必使用UNION ALL。還有一種情況大家可能會忽略掉,就是雖然要求幾個子集的併集需要過濾掉重複記錄,但由於腳本的特殊性,不可能存在重複記錄,這時便應該使用 UNION ALL,如xx模塊的某個查詢程序就曾經存在這種情況,見,由於語句的特殊性,在這個腳本中幾個子集的記錄絕對不可能重複,故可以改用UNION ALL)。
6.在WHERE 語句中,儘量避免對索引欄位進行計算操作
這個常識相信絕大部分開發人員都應該知道,但仍有不少人這麼使用,我想其中一個最主要的原因可能是為了編寫寫簡單而損害了性能,那就不可取了。9月份在對XX系統做性能分析時發現,有大量的後臺程序存在類似用法,如:where trunc(create_date)=trunc(:date1),雖然已對create_date 欄位建了索引,但由於加了TRUNC,使得索引無法用上。此處正確的寫法應該是where create_date>=trunc(:date1) and create_date< pre=""><>或者是where create_date between trunc(:date1) and trunc(:date1)+1-1/(24*60*60)。
注意:因between 的範圍是個閉區間(greater than or equal to low value and less than or equal to high value.),故嚴格意義上應該再減去一個趨於0的小數,這裡暫且設置成減去1秒(1/(24*60*60)),如果不要求這麼精確的話,可以略掉這步。
7.對Where 語句的法則
7.1 避免在WHERE子句中使用in,not in,or 或者having。
可以使用 exist 和not exist代替in和not in。
可以使用表連結代替 exist。Having可以用where代替,如果無法代替可以分兩步處理。
7.2 不要以字符格式聲明數字,要以數字格式聲明字符值。(日期同樣)否則會使索引無效,產生全表掃描。
例子使用:
--不要使用:
8.對Select語句的法則
在應用程式、包和過程中限制使用select * from table這種方式。看下面例子,需要用到哪些欄位就去查哪些欄位不要都差,表裡查數據很浪費時間。
--使用
--而不要使用
9. 排序
避免使用耗費資源的操作,帶有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL語句會啟動SQL引擎 執行,耗費資源的排序(SORT)功能. DISTINCT需要一次排序操作, 而其他的至少需要執行兩次排序。
10.臨時表
慎重使用臨時表可以極大的提高系統性能。
11.對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
12.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
可以在num上設置默認值0,確保表中num列沒有null值,然後這樣查詢(在項目開發中,一開始我寫的查詢語句加了null判斷,一位前輩指點我要多思考,無論是代碼還是庫表,應遵『循精簡有效『的原則):
13.應儘量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。
14.應儘量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
可以這樣查詢:
15.in 和 not in 也要慎用,否則會導致全表掃描,如:
select id from t where num in(1,2,3)
對於連續的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
16.下面的查詢也將導致全表掃描:
select id from t where name like '%abc%'
17.應儘量避免在 where 子句中對欄位進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where num/2=100
應改為:
select id from t where num=100*2
18.應儘量避免在where子句中對欄位進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)='abc'--name以abc開頭的id
select id from t where name like 'abc%'
19.不要在 where 子句中的「=」左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
20.在使用索引欄位作為條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,
否則該索引將不會被使用,並且應儘可能的讓欄位順序與索引順序相一致。
21.不要寫一些沒有意義的查詢,如需要生成一個空表結構:
select col1,col2 into #t from t where 1=0
這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:
create table #t(...)
22.很多時候用 exists 代替 in 是一個好的選擇:
select num from a where num in(select num from b)
用下面的語句替換:
select num from a where exists(select 1 from b where num=a.num)
23.並不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重複時,SQL查詢可能不會去利用索引,
如一表中有欄位sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。
24.索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,
因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。
一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。
25.儘量使用數字型欄位,若只含數值信息的欄位儘量不要設計為字符型,這會降低查詢和連接的性能,並會增加存儲開銷。
這是因為引擎在處理查詢和連接時會逐個比較字符串中每一個字符,而對於數字型而言只需要比較一次就夠了。
26.儘可能的使用 varchar 代替 char ,因為首先變長欄位存儲空間小,可以節省存儲空間,
其次對於查詢來說,在一個相對較小的欄位內搜索效率顯然要高些。
27.任何地方都不要使用 select * from t ,用具體的欄位列表代替「*」,不要返回用不到的任何欄位。
28.避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。
29.在新建臨時表時,如果一次性插入數據量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,
以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然後insert。
30.儘量避免使用遊標,因為遊標的效率較差,如果遊標操作的數據超過1萬行,那麼就應該考慮改寫。
31.使用基於遊標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。
32.儘量避免大事務操作,提高系統並發能力。
33.儘量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。
什麼是存儲過程
存儲過程是由流控制和SQL語句書寫的過程,這個過程經編譯和優化後存儲在資料庫伺服器中,應用程式使用時只要調用即可。在ORACLE中,若干個有聯繫的過程可以組合在一起構成程序包。
存儲過程優點
1. 速度快。存儲過程只在創造時進行編譯,以後每次執行存儲過程都不需再重新編譯,而一般SQL 語句每執行一次就編譯一次,所以使用存儲過程可提高資料庫執行速度。
2. 寫程序簡單。採用存儲過程調用類,調用任何存儲過程都只要1-2行代碼。
3. 升級、維護方便。存儲過程會使得維護起來更加方便,因為通常修改一個存儲過程要比在一個已經發布的組件中修改SQL語句更加方便;
4. 能夠緩解網絡帶寬。因為可以批量執行SQL語句而不是從客戶端發送超負載的請求。尤其對於較為複雜的邏輯,減少了網絡流量之間的消耗。
5. 可保證數據的安全性和完整性。通過存儲過程可以使沒有權限的用戶在控制之下間接地存取資料庫,從而保證數據的安全。通過存儲過程可以使相關的動作在一起發生,從而可以維護資料庫的完整性。
6. 增強安全性。
a) 通過向用戶授予對存儲過程(而不是基於表)的訪問權限,它們可以提供對特定數據的訪問。
b) 提高代碼安全,防止 SQL注入(但未徹底解決,例如,將數據操作語言--DML,附加到輸入參數)。
c) SqlParameter 類指定存儲過程參數的數據類型,作為深層次防禦性策略的一部分,可以驗證用戶提供的值類型(但也不是萬無一失,還是應該傳遞至資料庫前得到附加驗證)。
存儲過程缺點
1. 可移植性差。由於存儲過程將應用程式綁定到 SQL Server,因此使用存儲過程封裝業務邏輯將限制應用程式的可移植性。如果應用程式的可移植性在您的環境中非常重要,則將業務邏輯封裝在不特定於 RDBMS 的中間層中可能是一個更佳的選擇。
2. 代碼可讀性差,相當難維護。
3. 不支持群集
4. 大量採用存儲過程進行業務邏輯的開發致命的缺點是很多存儲過程不支持面向對象的設計,無法採用面向對象的方式將業務邏輯進行封裝,從而無法形成通用的可支持復用的業務邏輯框架。
5. 如果在一個程序系統中大量的使用存儲過程,到程序交付使用的時候隨著用戶需求的增加會導致數據結構的變化,接著就是系統的相關問題了,最後如果用戶想維護該系統可以說是很難很難、而且代價是空前的,維護起來更麻煩。
使用原則
1. 當一個業務同時對多個表進行處理的時候採用存儲過程比較合適。
2. 複雜的數據處理用存儲過程比較合適,如有些報表處理。
3. 多條件多表聯合查詢,並做分頁處理,用存儲過程也比較適合。
4. 使用存儲過程,等需求變動,需要維護的時候,麻煩就來了。不應該大規模使用。
5. 適當的使用存儲過程,能夠提高我們SQL查詢的性能,以便於提高我們的工作效率。
說說mysql和oracle他門的分頁查詢.分別是怎麼實現的
MySQL:
1. MySQL資料庫實現分頁比較簡單,提供了 LIMIT函數。一般只需要直接寫到sql語句後面就行了。
2. LIMIT子 句可以用來限制由SELECT語句返回過來的數據數量,它有一個或兩個參數,如果給出兩個參數, 第一個參數指定返回的第一行在所有數據中的位置,從0開始(注意不是1),第二個參數指定最多返回行數。例如:
select * from table WHERE … LIMIT 10; #返回前10行
select * from table WHERE … LIMIT 0,10; #返回前10行
select * from table WHERE … LIMIT 10,20; #返回第10-20行數據
Oracle:
在oracle中沒有limit關鍵字,但是有 rownum欄位,rownum是一個偽列,是oracle系統自動為查詢返回結果的每行分配的編號,第一行為1,第二行為2,以此類推..
1. 第一種代碼如下:
l 其中最內層的查詢SELECT * FROM TABLE_NAME表示不進行翻頁的原始查詢語句。ROWNUM <= 40和RN >= 21控制分頁查詢的每頁的範圍。
l 上面給出的這個分頁查詢語句,在大多數情況擁有較高的效率。分頁的目的就是控制輸出結果集大小,將結果儘快的返回。在上面的分頁查詢語句中,這種考慮主要體現在WHERE ROWNUM <= 40這句上。
l 選擇第21到40條記錄存在兩種方法,一種是上面例子中展示的在查詢的第二層通過ROWNUM <= 40來控制最大值,在查詢的最外層控制最小值。而另一種方式是去掉查詢第二層的WHERE ROWNUM <= 40語句,在查詢的最外層控制分頁的最小值和最大值。
2. 第二種代碼如下:
l 紅色部分:按照工資降序排序並查詢所有的信息。
l 棕色部分:得到紅色部門查詢的值,並查詢出系統的rownum並指定上別名。這一句就比較關鍵,起了一個過渡的作用,首先要算出rownum來對紅色部分指定上序號,也可以為藍色外面部分用到這個變量。指定上查詢的開始記錄數和結束記錄的條件。
l 藍色部分:指定記錄從第幾條開始到第幾條結束,取出棕色部門的值來作為查詢條件的變量
總結:絕大多數的情況下,第一個查詢的效率比第二個高得多。
oracle如果要實現主鍵自增.怎麼實現?mysql呢
要實現主鍵的自動遞增非常簡單.只需要在主鍵定義的後面加上auto_increment即可,
1. 建立一個表,
2. 建立一個sequence序列:
3. 建立一個觸發器:
資料庫優化:電商項目中設計某個商品表的過程當中,為什麼要按照下圖設計
1. 數據細分:
電商項目一般有三個主要業務:查詢、下單和付款,其中下單只涉及商品id、商品價格、商品數量和商品金額,將這四個屬性單獨創建一張表,可以降低查詢和下單業務之間的影響,必要的話,還可以將查詢和下單拆分成兩個獨立的系統。
2. 數據安全:
商品金額是計算好保存到資料庫的,在使用時不用去界面獲取,防止有人惡意篡改界面數據。很多電商網站如果涉及不嚴密就有可乘之機,虛假傳遞數據擾亂後臺判斷。
總之,寫好一個sql語句並不只是單單查詢結果正確就萬事大吉了,在查詢結果正確的前提下,要優化sql語句,提高效率。寫好sql語句並不是一朝一夕,需要日積月累,下一個項目開發過程中,肯定比上一個項目做的要好,不斷開發,不斷學習,加油!!!