# 多表查詢優化
## (1)基本連接方法(內連接、外連接):
一)內連接:用比較運算符根據每個表共有的列的值匹配兩個表中的行(=或>、
意思是:檢索商品分類和商品表“分類描述”相同的行
~~~
select
? ? ? ? d.Good_ID ,
? ? ? ? d.Classify_ID,
? ? ? ? d.Good_Name
? ? ? ? from
? ? ? ? Commodity_list d
? ? ? ? inner join commodity_classification c
? ? ? ? on d.Classify_Description=c.Good_kinds_Name
~~~
得到的滿足某一條件的是A,B內部的數據;正因為得到的是內部共有數據,所以連接方式稱為內連接。

二)外連接之左連接
~~~
//意思:查得商品分類表的所有數據,以及滿足條件的商品詳情表的數據
select
? ? ? ? *
? ? ? ? from
? ? ? ? commodity_classification c
? ? ? ? left join commodity_list d
? ? ? ? on d.Classify_Description=c.Good_kinds_Name
~~~
首先是左表數據全部羅列,然后有滿足條件的右表數據都會全部羅列出。若兩條右表數據對左表一條數據,則會用對應好的左表數據補足作為一條記錄。
~~~
左連接升級:
[left join 或者left outer join(等同于left join)] + [where B.column is null]
//就是只查分類表數據,但是減去跟商品詳情表有聯系的數據。
select
? ? ? ? *
? ? ? ? from
? ? ? ? commodity_classification c
? ? ? ? left join commodity_list d
? ? ? ? on d.Classify_Description=c.Good_kinds_Name
? ? ? ? where d.Classify_Description is null
~~~
三)外連接之右連接
~~~
//意思是查得商品詳情表的所有數據以及在分類描述相同條件下的商品分類表數據
select
? ? ? ? *
? ? ? ? from
? ? ? ? commodity_classification c
? ? ? ? right join commodity_list d
? ? ? ? on d.Classify_Description=c.Good_kinds_Name
~~~
與左連恰恰相反,首先是右表數據全部羅列,然后有滿足條件的左表數據都會全部羅列出。若兩條左表數據對右表一條數據,則會用對應好的右表數據補足作為一條記錄。
右連接升級:
//意思:查詢商品詳情表的所有數據,但是要減去和商品分類表有聯系的數據
~~~
select
? ? ? ? *
? ? ? ? from
? ? ? ? commodity_classification c
? ? ? ? right join commodity_list d
? ? ? ? on d.Classify_Description=c.Good_kinds_Name
? ? ? ? where c.Good_kinds_Name is null ?
~~~
# 查詢編寫的注意點:
(1)對查詢進行優化,要盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
(2)應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
~~~
//最好不要給數據庫留NULL,盡可能的使用 NOT NULL填充數據庫.
select id from t where num is null
~~~
備注、描述、評論之類的可以設置為 NULL,其他最好不要使用NULL。
不要以為 NULL 不需要空間,比如:char(100) 型,在字段建立時,空間就固定了, 不管是否插入值(NULL也包含在內),都是占用 100個字符的空間的,如果是varchar這樣的變長字段, null 不占用空間。
可以在num上設置默認值0,確保表中num列沒有null值,然后這樣查詢:
`select id from t where num = 0`
(3)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
~~~
~~~
很多時候用 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)
~~~
(4)下面的查詢也將導致全表掃描:
~~~
select id from t where name like ‘%abc%’
~~~
若要提高效率,可以考慮全文檢索。
(5)盡量使用數字型字段,若只含數值信息的字段盡量不要設計為字符型,這會降低查詢和連接的性能,并會增加存儲開銷。這是因為引擎在處理查詢和連 接時會逐個比較字符串中每一個字符,而對于數字型而言只需要比較一次就夠了。
(6)任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。
(7)盡量使用表變量來代替臨時表。如果表變量包含大量數據,請注意索引非常有限(只有主鍵索引)。
(8)在Join表的時候使用相當類型的例,并將其索引
如果你的應用程序有很多 JOIN 查詢,你應該確認兩個表中Join的字段是被建過索引的。這樣,MySQL內部會啟動為你優化Join的SQL語句的機制。
而且,這些被用來Join的字段,應該是相同的類型的。例如:如果你要把 DECIMAL 字段和一個 INT 字段Join在一起,MySQL就無法使用它們的索引。對于那些STRING類型,還需要有相同的字符集才行。(兩個表的字符集有可能不一樣)
~~~
//在state中查找company
SELECT company_name FROM users
? ? LEFT JOIN companies ON (users.state = companies.state)
? ? WHERE users.id = $user_id"
? ? //兩個 state 字段應該是被建過索引的,而且應該是相當的類型,相同的字符集
~~~