當前位置:首頁 » 編程語言 » sql中的驅動表
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

sql中的驅動表

發布時間: 2022-12-20 10:53:26

A. 表連接中的驅動表與被驅動表

mysql中的表連接分為三種

1. 左連接 left join
左連接以左表為基礎,查詢出左表所有數據並且去匹配右表的數據,如果右表沒
有數據,則為空

2. 右連接 right join
右連接以右表為基礎,查詢出右表所有數據並且去匹配左表的數據,如果左表沒
有數據,則為空

3. 內連接 inner join
內連接會把左右表匹配的數據查詢出來,不存在的數據直接忽略

驅動表與被驅動表的概念
驅動表是表連接中的基礎表,也就是通過驅動表的數據結果集作為循環基礎數據,然後一條一條的通過這個結果集的數據作為過濾條件到被驅動表中查詢數據,然後合並

驅動與被驅動
左連接中 左表是驅動表,右表是被驅動表
右連接中 右表是驅動表,左表是被驅動表
內連接中 表數據量較小的表會由mysql自動選擇作為驅動表去驅動大表
有一個重點是,如果where條件存在的話 mysql會根據where實際條件進行驅動表的選擇
sql優化中,一個比較重要的點就是要用小表驅動大表

原因
mysql表關聯的演算法,是通過驅動表去循環被驅動表,比如說,20w的大表和200條的小表,如果大表驅動,那麼是20w條記錄外循環,內循環200條去連接查找,需要通過20w次連接,如果小表驅動,那麼是200條記錄外循環,內循環20w條去連接查找,只需要通過200次連接就可以了,並且驅動表是不會使用索引的

B. sql把最小的表作為驅動表(基礎表),為什麼能提高效率

驅動表是要全表掃描的,所以記錄越少效率就會越高,而且要放在FROM子句中,表名列表的最後。當然這也不是絕對的,很多時候要考慮結果完整性及業務實際需求。

C. mysql在連表查詢時是小表驅動大表嗎

你那樣寫邏輯都變化了
假定你要選擇的b的field位bf
這昂寫就可以了,XXX是要選擇的欄位列表(不包含b.bf)
SELECT xxx,
CASE b.num WHEN 1 THEN b.bf ELSE NULL END
from a left join b on b.opuid=a.uid
where a.true=1
不知道mysql支持不支持case when,也就是作了一個判斷if b.num =1 then b.bf else null

D. SQL執行順序

查詢語句中select from where group by having order by的執行順序

1.查詢中用到的關鍵詞主要包含六個,並且他們的順序依次為 

select--from--where--group by--having--order by 

其中select和from是必須的,其他關鍵詞是可選的,這六個關鍵詞的執行順序 

與sql語句的書寫順序並不是一樣的,而是按照下面的順序來執行 

from--where--group by--having--select--order by, 

from:需要從哪個數據表檢索數據 

where:過濾表中數據的條件 

group by:如何將上面過濾出的數據分組 

having:對上面已經分組的數據進行過濾的條件  

select:查看結果集中的哪個列,或列的計算結果 

order by :按照什麼樣的順序來查看返回的數據

2.from後面的表關聯,是自右向左解析的 

而where條件的解析順序是自下而上的。 

也就是說,在寫SQL文的時候,盡量把數據量大的表放在最右邊來進行關聯, 

而把能篩選出大量數據的條件放在where語句的最下面。

SQL Select語句完整的 執行順序 【從DBMS使用者角度】:

1、from子句組裝來自不同數據源的數據;

2、where子句基於指定的條件對記錄行進行篩選;

3、group by子句將數據劃分為多個分組;

4、使用聚集函數進行計算;

5、使用having子句篩選分組;

6、計算所有的表達式;

7、使用order by對結果集進行排序 。

from 子句--執行順序為從後往前、從右到左

表名(最後面的那個表名為驅動表,執行順序為從後往前, 所以數據量較少的表盡量放後)

oracle 的解析器按照從右到左的順序處理,FROM 子句中的表名,FROM 子句中寫在最後的表(基礎表 driving

table)將被最先處理,即最後的表為驅動表,在FROM 子句中包含多個表的情況下,你必須選擇記錄條數最少的表作為基礎表。如果有3

個以上的表連接查詢, 那就需要選擇交叉表(intersection table)作為基礎表, 交叉表是指被其他表所引用的表

多表連接時,使用表的別名並把別名前綴於每個Column上。可以減少解析的時間並減少那些由Column 歧義引起的語法錯誤.

where子句--執行順序為自下而上、從右到左

ORACLE 採用自下而上從右到左的順序解析Where 子句,根據這個原理,表之間的連接必須寫在其他Where 條件之前, 可以過濾掉最大數量記錄的條件必須寫在Where 子句的末尾。

group by--執行順序從左往右分組

提高GROUP BY 語句的效率, 可以通過將不需要的記錄在GROUP BY 之前過濾掉。即在GROUP BY前使用WHERE來過慮,而盡量避免GROUP BY後再HAVING過濾。

having 子句----很耗資源,盡量少用

避免使用HAVING 子句, HAVING 只會在檢索出所有記錄之後才對結果集進行過濾. 這個處理需要排序,總計等操作.

如果能通過Where 子句在GROUP BY前限制記錄的數目,那就能減少這方面的開銷.

(非oracle 中)on、where、having 這三個都可以加條件的子句中,on 是最先執行,where 次之,having 最後,因為on 是先把不符合條件的記錄過濾後才進行統計,它就可以減少中間運算要處理的數據,按理說應該速度是最快的,

where 也應該比having 快點的,因為它過濾數據後才進行sum,在兩個表聯接時才用on 的,所以在一個表的時候,就剩下where 跟having比較了。

在這單表查詢統計的情況下,如果要過濾的條件沒有涉及到要計算欄位,那它們的結果是一樣的,只是where 可以使用rushmore 技術,而having 就不能,在速度上後者要慢。

如果要涉及到計算的欄位,就表示在沒計算之前,這個欄位的值是不確定的,where 的作用時間是在計算之前就完成的,而having 就是在計算後才起作用的,所以在這種情況下,兩者的結果會不同。

在多表聯接查詢時,on 比where 更早起作用。系統首先根據各個表之間的聯接條件,把多個表合成一個臨時表後,再由where 進行過濾,然後再計算,計算完後再由having 進行過濾。

由此可見,要想過濾條件起到正確的作用,首先要明白這個條件應該在什麼時候起作用,然後再決定放在那裡。

select子句--少用*號,盡量取欄位名稱 。

ORACLE 在解析的過程中, 會將依次轉換成所有的列名, 這個工作是通過查詢數據字典完成的, 使用列名意味著將減少消耗時間。

sql 語句用大寫的;因為 oracle 總是先解析 sql 語句,把小寫的字母轉換成大寫的再執行

order by子句--執行順序為從左到右排序,很耗資源

E. 從哪些方面,sql語句性能如何分析

一段SQL代碼寫好以後,可以通過查看SQL的執行計劃,初步預測該SQL在運行時的性能好壞,尤其是在發現某個SQL語句的效率較差時,我們可以通過查看執行計劃,分析出該SQL代碼的問題所在。

1、 打開熟悉的查看工具:PL/SQL Developer。
在PL/SQL Developer中寫好一段SQL代碼後,按F5,PL/SQL Developer會自動打開執行計劃窗口,顯示該SQL的執行計劃。

2、 查看總COST,獲得資源耗費的總體印象
一般而言,執行計劃第一行所對應的COST(即成本耗費)值,反應了運行這段SQL的總體估計成本,單看這個總成本沒有實際意義,但可以拿它與相同邏輯不同執行計劃的SQL的總體COST進行比較,通常COST低的執行計劃要好一些。

3、 按照從左至右,從上至下的方法,了解執行計劃的執行步驟
執行計劃按照層次逐步縮進,從左至右看,縮進最多的那一步,最先執行,如果縮進量相同,則按照從上而下的方法判斷執行順序,可粗略認為上面的步驟優先執行。每一個執行步驟都有對應的COST,可從單步COST的高低,以及單步的估計結果集(對應ROWS/基數),來分析表的訪問方式,連接順序以及連接方式是否合理。

4、 分析表的訪問方式
表的訪問方式主要是兩種:全表掃描(TABLE ACCESS FULL)和索引掃描(INDEX SCAN),如果表上存在選擇性很好的索引,卻走了全表掃描,而且是大表的全表掃描,就說明表的訪問方式可能存在問題;若大表上沒有合適的索引而走了全表掃描,就需要分析能否建立索引,或者是否能選擇更合適的表連接方式和連接順序以提高效率。

5、 分析表的連接方式和連接順序
表的連接順序:就是以哪張表作為驅動表來連接其他表的先後訪問順序。
表的連接方式:簡單來講,就是兩個表獲得滿足條件的數據時的連接過程。主要有三種表連接方式,嵌套循環(NESTED LOOPS)、哈希連接(HASH JOIN)和排序-合並連接(SORT MERGE JOIN)。我們常見得是嵌套循環和哈希連接。
嵌套循環:最適用也是最簡單的連接方式。類似於用兩層循環處理兩個游標,外層游標稱作驅動表,Oracle檢索驅動表的數據,一條一條的代入內層游標,查找滿足WHERE條件的所有數據,因此內層游標表中可用索引的選擇性越好,嵌套循環連接的性能就越高。
哈希連接:先將驅動表的數據按照條件欄位以散列的方式放入內存,然後在內存中匹配滿足條件的行。哈希連接需要有合適的內存,而且必須在CBO優化模式下,連接兩表的WHERE條件有等號的情況下才可以使用。哈希連接在表的數據量較大,表中沒有合適的索引可用時比嵌套循環的效率要高。

F. 多表關聯查詢的SQL執行原理

平時大多是執行單表查詢,通常你把索引建好,讓他盡可能走索引,性能都沒問題。但其實也有不少的多表關聯語句,因為有時查找目標數據,不得不藉助多表關聯的語法,才能實現你想要但使用多表關聯的時候,你的SQL性能就可能會遇到一些問題。

若在FROM字句後直接來兩個表名,就是要針對兩個表進行查詢,而且會把兩個表的數據給關聯,假設你未限定多表連接條件,可能會搞出一個笛卡爾積。所以通常都會在多表關聯語句中的WHERE子句里引入一些關聯條件:where t1.x1=xxx and t1.x2=t2.x2 and t2.x3=xxx

假設:

所以該SQL執行過程可能是:

他可能是先從一個表裡查一波數據:驅動表

再根據這波數據去另外一個表裡查一波數據進行關聯,另外一個表叫:被驅動表

員工表包含id(主鍵)、name(姓名)、department(部門)

產品銷售業績表裡包含id(主鍵)、employee_id(員工id)、產品名稱(proct_name)、銷售業績(saled_amount)。

現在要看每個員工對每個產品的銷售業績:

此時看到的數據:

全表掃描員工表,找出每個員工,然後針對每個員工的id去業績表找 employee_id 跟員工id相等的數據,可能每個員工的id在業績表裡都會找到多條數據,因為他可能有多個產品的銷售業績。

然後把每個員工數據跟他在業績表裡找到的所有業績數據都關聯,比如:

內連接,inner join,要求兩個表裡的數據必須完全能關聯上,才能返回。

假設員工表裡有個人是新員工,入職到現在無銷售業績,此時還是希望能夠查出來該員工的數據,只不過他的銷售業績那塊可以給個NULL,表示無業績。但若僅使用上述SQL語法,似乎搞不定,因為必須要兩個表能關聯上的數據才查得出來。

此時就需要

outer join,分為:

還有個語法限制,如果你是內連接,那連接條件可以放在where語句,但外連接一般是把連接條件放在ON語句:

一般寫多表關聯,主要就是內連接和外連接。

G. MySQL表連接之驅動表與被驅動表

眾所周知, MySQL的驅動表與被驅動表是優化器自動優化選擇的結果 (與表連接的前後順序等無關),我們可以用explain執行計劃來知曉:

如上所示,前面一行t1是驅動表,後面一行t2是被驅動表。那麼驅動表與被驅動表的選擇是否有規律可循呢?下面是網路搜索兩個主流的博文對驅動表與被驅動表的闡釋:
1. MySQL連接查詢驅動表被驅動表以及性能優化 - 阿偉~ - 博客園 博文A 主要結論:

2. mysql驅動表與被驅動表及join優化_java小小小黑的博客-CSDN博客_mysql驅動表和被驅動表 博文B 其主要結論:

兩個帖子的結論是都差不多,而且還給出了例子來佐證。那麼網上的結論是否權威?是否有普遍性?是否存在缺陷?

讓我們來一起打破砂鍋問到底。下面有兩張表結構一模一樣的表t1,t2:其中t1 100條數據,t2 1000條數據;t1(t2)結構如下:

按照上面博文的結論,left join左邊是t2表,應該是驅動表。我們查看下結果:

與 博文B 中觀點1相違背(同理觀點2也違背),與實際不符,但究竟這是為什麼呢?
下面發一張MySQL的執行過程(來源於《MySQL實戰45講》中01講【一條SQL查詢語句是如何執行的】)

so die si ne,原來sql執行的過程是這樣呀。等等,不對,這跟剛才SQL又有什麼關系,上面left join中t2表還是左邊的呀。

我們知道MySQL高版本的性能越來越好,它是不斷進行優化迭代的。遠古的mysql版本可能還需要人工把小表放在前面,大表放在後面等這些需要人工調優的經驗早就已經被解決了。也就是說我們寫的語句,MySQL為了追求更好的效率,它在執行器執行前已經幫我們優化了。那麼實際優化後的sql如何查看呢?用show warning命令:

其中Message就是優化後實際執行的sql語句,格式化後如下:

優化後left join左連接變成了內連接(inner) join。所以用優化後的sql看,表t1是小表所以作為驅動表,與實際結果相符。

left join 竟然優化成了join,太神奇了,但這是為什麼呢?原因在於mysql中null與任何值做等值或者不等值比較的時候都是null,即使是select null=null 也是null。這樣where 條件t1.a=t2.a查詢條件不會包含t2.a為NULL的行,實際效果其實跟join一樣,被優化器智能的優化了。

我們直接看執行計劃看實際結果吧:

結果顯示t2是驅動表,t1是被驅動表。t2是1000條數據按理說是大表應該是被驅動表,與 博文A , 博文B 的結論又不一致了。

《MySQL實戰45講》中34講【到底可不可以使用join】已經講的很透徹了,很深入了,我就不在這里獻丑了。啰嗦幾句大概就是驅動表是全表掃描不走索引,所以選被驅動表t1可以走索引,不會全表掃描,減少IO次數,性能高。裡面對大表小表的總結,簡直是精髓,特意在此再次著重強調:

在決定哪個表做驅動表的時候,應該是兩個表按照各自的條件過濾,過濾完成之後,計算參與join的各個欄位的總數據量,數據量小的那個表,就是「小表」,應該作為驅動表。

按照上面分析,我們先獨立思考下MySQL會選擇哪張表作為驅動表呢?

表t1,t2在欄位a上都有索引不會全表掃描,其中t1.a=5條件過濾後只有一條,很顯然嘛,t1數據量少是小表,肯定是驅動表,錯不了,再說了前面的紅色粗體已經強調了,不會有錯的。

有冇搞錯?事實又被打臉了。還記得在開篇我們說過的mysql優化器會對sql語句進行優化的嗎?下面我們看下執行計劃與優化的sql語句:

格式化後的優化SQL如下:

優化後兩表t1,t2都走索引,並且都只有一條結果返回,因此都只會掃描一行,數據量一樣,所以誰在前面誰就是驅動表,也就是上面sql中表t2。一切都釋然,豁然開通!

回頭再仔細想想,高,實在是高!仔細深思之後MySQL優化後的句子真讓人猛拍大腿。高明之處在於:
1. 本來join連接是個M*N的嵌套循環,優化後變成了M+N的判斷,兩表不再嵌套判斷了。
2. 優化後,兩表沒有多大必然聯系,只需把兩表的結果集拼接即可,互不幹擾。如果mysql未來可以多線程查詢,豈不十分快哉!

小夥伴們還記得我們在上一章 MySQL索引初探 中編碼類型不一致發生隱式轉換時有時候走索引,有時候索引又失效的問題嗎?下面我們選取有代表性的一條記錄來分析:

其中表demo_test總共有640條數據,demo_test_ass有3條數據。顯然經過過濾條件t.rid>1完成後demo_test_ass數據量小,應該作為驅動表。雖然test.c_utf8mb4 = t.c2兩欄位連接中發生了t.c2欄位發生隱式轉換,但是實際上並不影響被驅動表test上的c_utf8mb4索引。

好了,本章到此結束,讓我們一起 總結一下MySQL驅動表與被驅動表的選取原則

หน ง 同等條件,優先選取有索引的表作為被驅動表。 在此介紹一下什麼叫同等條件,比如上面的②中的語句。 兩表沒有其他額外的過濾條件,因此選關聯欄位有索引的t1作為被驅動表。但是如果加了條件(and t1.id=3),此時t1數據量少,就選取了t2作為被驅動表。

สอง MySQL選擇驅動表與被驅動表是基於優化器優化後的,小表是驅動表,大表是被驅動表。 基於優化器優化後開篇的 博文A與B 結論成立。

當然這都是我一家之言,並不是官方結論,目前暫未找到官方確切對於驅動表與被驅動表的解釋,請大家踴躍拍磚!

H. 優化SQL語句

一.常規SQL語句優化

1.不用*來代替所有列名,盡量採用與訪問表相關的實際列名;

2.用TRUNCATE 代替DELETE

3.在確保完整性的情況下,多使用COMMIT語句。

4.盡量減少表的查詢次數。

二.表連接優化

1.驅動表的選擇:

驅動表是指被最先訪問的表;

2.where子句連接順序

表連接最好都在where條件以前

三.合理使用索引

從總行中查詢2%-4%的表,可以考慮建立索引

建立索引的基本原則:

1.以查詢關鍵字為基礎,表中的行隨機排列

2.包含的列數相對較少的表

3.表中大多數查詢都包含相對簡單的WHERE從句

4.以查詢關鍵字作為基礎表,且該表中的行遵循均勻分布

5.緩存命中率低,並且不需要操作系統許可權

選擇索引列的原則:

1.WHERE從句經常使用的關鍵字

2.SQL語句中頻繁使用的表連接的關鍵字

3.可選擇性高的關鍵字

4.取值較少的關鍵字或表達式

5.不要把頻繁修改的列作為索引列

6.不要使用包含操作符或函數的WHERE從句中的關鍵字作為索引

7.如果大量並發的INSERT,UPDATE,DELETE語句訪問了父表或者子表,則考慮使用完整性約束的外部鍵作為索引

8.在選擇索引時,要考慮改索引所引起的INSERT UPDATE,DELETE操作是否值得

I. 13.MySQL聯表查詢中的驅動表,優化查詢,以小表驅動大表

=========================總結===========================
1.開啟慢查詢日誌,設置閥值,比如超過5秒就是慢SQL,並把它抓取出來。
2.explain+慢SQL 分析
3.show profile 查詢SQL在MySQL伺服器裡面的執行細節和聲明周期。

J. sql中in和exist語句的區別

兩者都能實現表功能查詢,主要區別如下:

1、適用表的類型不同。

in是子查詢為驅動表,外面的表為被驅動表,故適用於子查詢結果集小而外面的表結果集大的情況。

exists是外面的表位驅動表,子查詢裡面的表為被驅動表,故適用於外面的表結果集小而子查詢結果集大的情況。

2、子查詢關聯不同。

exists一般都是關聯子查詢。對於關聯子查詢,必須先執行外層查詢,接著對所有通過過濾條件的記錄,執行內層查詢。外層查詢和內層查詢相互依賴,因為外層查詢會把數據傳遞給內層查詢。

in則一般都是非關聯子查詢,非關聯子查詢則必須先完成內層查詢之後,外層查詢才能介入。

3、執行次數不同。

IN 語句:只執行一次,確定給定的值是否與子查詢或列表中的值相匹配。in在查詢的時候,首先查詢子查詢的表,然後將內表和外表做一個笛卡爾積,然後按照條件進行篩選。所以相對內表比較小的時候,in的速度較快。

EXISTS語句:執行次數根據表的長度而定。指定一個子查詢,檢測行的存在。遍歷循環外表,然後看外表中的記錄有沒有和內表的數據一樣的。匹配上就將結果放入結果集中。