mysql带where的join加索引_MySQL索引分析和优化+JOIN的分类(转)

join :

左右合併

inner join : 只顥示符合修件的資料列 (左右互相比對)

left join : 顥示符合條件的右資料列及左邊不符合條件的資料列

(此時右邊的資料會以 NULL 顯示)

right join : 顥示符合條件的左資料列及左邊不符合條件的資料列

(此時左邊的資料會以 NULL 顯示)

full join : 顥示符合條件的料列及左邊+右邊不符合條件的資料列

(此時缺乏資料的資料列會以 NULL 顯示)

cross join :

直接將一個資料表的每一筆資料列和另一個料表的每一筆資料列搭配成新的資料列

self-joins : 自己join 自己

更多 :

union : 合併多個查尋結果 (上下垂直合併)

subquery : 子查尋

index :

索引可以加快查尋速度,以平衡樹結構存放索引資料 .

例如:

當我們要找編碼N的記錄時,可從根節點開始往下找,

假設有M層則只要找M次,但是如果不設索引則要找N次

唯一索引(非叢集索引 : UNIQUE INDEX) :

會依單一欄位以順序的方式做排序放在前一個記錄的後面

資料表中的任何索引值都不可以相同.有點像PRIMARY KEY .

復合索引(叢集索引 : COMPOSITE INDEX) :

如果是唯一索引又是復合索引則多個欄位組合起來的值

不可以重復而單一欄位則可以重復.

二、索引的類型

MySQL提供多種索引類型供選擇:

普通索引

這是最基本的索引類型,而且它沒有唯一性之類的限制。普通索引可以通過以下幾種方式創建:

創建索引,例如CREATE INDEX ON tablename

(列的列表);

修改表,例如ALTER TABLE tablename ADD INDEX [索引的名字]

(列的列表);

創建表的時候指定索引,例如CREATE TABLE tablename ( [...], INDEX

[索引的名字] (列的列表) );

唯一性索引

這種索引和前面的「普通索引」基本相同,但有一個區別:索引列的所有值都只能出現一次,即必須唯一。唯一性索引可以用以下幾種方式創建:

創建索引,例如CREATE UNIQUE INDEX ON tablename

(列的列表);

修改表,例如ALTER TABLE tablename ADD UNIQUE [索引的名字]

(列的列表);

創建表的時候指定索引,例如CREATE TABLE tablename ( [...], UNIQUE

[索引的名字] (列的列表) );

主鍵

主鍵是一種唯一性索引,但它必須指定為「PRIMARY

KEY」。如果你曾經用過AUTO_INCREMENT類型的列,你可能已經熟悉主鍵之類的概念了。主鍵一般在創建表的時候指定,例如「CREATE

TABLE tablename ( [...], PRIMARY KEY (列的列表) );

」。但是,我們也可以通過修改表的方式加入主鍵,例如「ALTER TABLE

tablename ADD PRIMARY KEY (列的列表);

」。每個表只能有一個主鍵。

全文索引

MySQL從3.23.23版開始支持全文索引和全文檢索。在MySQL中,全文索引的索引類型為FULLTEXT。全文索引可以在VARCHAR或者

TEXT類型的列上創建。它可以通過CREATE TABLE命令創建,也可以通過ALTER

TABLE或CREATE INDEX命令創建。對於大規模的數據集,通過ALTER

TABLE(或者CREATE

INDEX)命令創建全文索引要比把記錄插入帶有全文索引的空表更快。本文下面的討論不再涉及全文索引,要瞭解更多信息,請參見MySQL

documentation。

三、單列索引與多列索引

索引可以是單列索引,也可以是多列索引。下面我們通過具體的例子來說明這兩種索引的區別。假設有這樣一個people表:

CREATE TABLE people ( peopleid SMALLINT NOT NULL

AUTO_INCREMENT, firstname CHAR(50) NOT NULL, lastname CHAR(50) NOT

NULL, age SMALLINT NOT NULL, townid SMALLINT NOT NULL, PRIMARY KEY

(peopleid) );

這個數據片段中有四個名字為「Mikes」的人(其中兩個姓Sullivans,兩個姓McConnells),有兩個年齡為17歲的人,還有一個名字與眾不同的Joe

Smith。

這個表的主要用途是根據指定的用戶姓、名以及年齡返回相應的peopleid。例如,我們可能需要查找姓名為Mike

Sullivan、年齡17歲用戶的peopleid(SQL命令為SELECT peopleid FROM

people WHERE firstname='Mike' AND lastname='Sullivan' AND

age=17;)。由於我們不想讓MySQL每次執行查詢就去掃瞄整個表,這裡需要考慮運用索引。

首先,我們可以考慮在單個列上創建索引,比如firstname、lastname或者age列。如果我們創建firstname列的索引(ALTER

TABLE people ADD INDEX firstname

(firstname);),MySQL將通過這個索引迅速把搜索範圍限制到那些firstname='Mike';的記錄,然後再在這個「中間結果集」上進行其他條件的搜索:它首先排除那些lastname不等於「Sullivan」的記錄,然後排除那些age不等於17

的記錄。當記錄滿足所有搜索條件之後,MySQL就返回最終的搜索結果。

由於建立了firstname列的索引,與執行表的完全掃瞄相比,MySQL的效率提高了很多,但我們要求MySQL掃瞄的記錄數量仍舊遠遠超過了實際所需要的。雖然我們可以刪除firstname列上的索引,再創建lastname或者age列的索引,但總地看來,不論在哪個列上創建索引搜索效率仍舊相似。

為了提高搜索效率,我們需要考慮運用多列索引。如果為firstname、lastname和age這三個列創建一個多列索引,MySQL只需一次檢索就能夠找出正確的結果!下面是創建這個多列索引的SQL命令:

ALTER TABLE people ADD INDEX fname_lname_age

(firstname,lastname,age);

由於索引文件以B-樹格式保存,MySQL能夠立即轉到合適的firstname,然後再轉到合適的lastname,最後轉到合適的age。在沒有掃瞄數據文件任何一個記錄的情況下,MySQL就正確地找出了搜索的目標記錄!

那麼,如果在firstname、lastname、age這三個列上分別創建單列索引,效果是否和創建一個firstname、lastname、

age的多列索引一樣呢?答案是否定的,兩者完全不同。當我們執行查詢的時候,MySQL只能使用一個索引。如果你有三個單列的索引,MySQL會試圖選擇一個限制最嚴格的索引。但是,即使是限制最嚴格的單列索引,它的限制能力也肯定遠遠低於firstname、lastname、age這三個列上的多列索引。

四、最左前綴

多列索引還有另外一個優點,它通過稱為最左前綴(Leftmost

Prefixing)的概念體現出來。繼續考慮前面的例子,現在我們有一個firstname、lastname、age列上的多列索引,我們稱這個索引為fname_lname_age。當搜索條件是以下各種列的組合時,MySQL將使用fname_lname_age索引:

firstname,lastname,age

firstname,lastname

firstname

從另一方面理解,它相當於我們創建了(firstname,lastname,age)、(firstname,lastname)以及(firstname)這些列組合上的索引。下面這些查詢都能夠使用這個fname_lname_age索引:

SELECT peopleid FROM people WHERE

firstname='Mike' AND lastname='Sullivan' AND age='17'; SELECT

peopleid FROM people WHERE firstname='Mike' AND

lastname='Sullivan'; SELECT peopleid FROM people WHERE

firstname='Mike'; The following queries cannot use the index at

all: SELECT peopleid FROM people WHERE lastname='Sullivan'; SELECT

peopleid FROM people WHERE age='17'; SELECT peopleid FROM people

WHERE lastname='Sullivan' AND age='17';

五、選擇索引列

在性能優化過程中,選擇在哪些列上創建索引是最重要的步驟之一。可以考慮使用索引的主要有兩種類型的列:在WHERE子句中出現的列,在join子句中出現的列。請看下面這個查詢:

SELECT age ## 不使用索引

FROM people

WHERE firstname='Mike' ## 考慮使用索引

這個查詢與前面的查詢略有不同,但仍屬於簡單查詢。由於age是在SELECT部分被引用,MySQL不會用它來限制列選擇操作。因此,對於這個查詢來說,創建age列的索引沒有什麼必要。下面是一個更複雜的例子:

SELECT people.age, ##不使用索引

town.name ##不使用索引

FROM people LEFT JOIN town ON

people.townid=town.townid ##考慮使用索引

WHERE firstname='Mike' ##考慮使用索引

AND lastname='Sullivan' ##考慮使用索引

與前面的例子一樣,由於firstname和lastname出現在WHERE子句中,因此這兩個列仍舊有創建索引的必要。除此之外,由於town表的townid列出現在join子句中,因此我們需要考慮創建該列的索引。

那麼,我們是否可以簡單地認為應該索引WHERE子句和join子句中出現的每一個列呢?差不多如此,但並不完全。我們還必須考慮到對列進行比較的操作符類型。MySQL只有對以下操作符才使用索引:,>=,BETWEEN,IN,以及某些時候的LIKE。可以在

LIKE操作中使用索引的情形是指另一個操作數不是以通配符(%或者_)開頭的情形。例如,

「SELECT peopleid FROM people WHERE firstname

LIKE 'Mich%';」這個查詢將使用索引,但「SELECT

peopleid FROM people WHERE firstname LIKE

'%ike';」這個查詢不會使用索引。

六、分析索引效率

現在我們已經知道了一些如何選擇索引列的知識,但還無法判斷哪一個最有效。MySQL提供了一個內建的SQL命令幫助我們完成這個任務,這就是

EXPLAIN命令。EXPLAIN命令的一般語法是:EXPLAIN

。你可以在MySQL文檔找到有關該命令的更多說明。下面是一個例子:

EXPLAIN SELECT peopleid FROM people WHERE firstname='Mike' AND

lastname='Sullivan' AND age='17';

這個命令將返回下面這種分析結果:

table

type

possible_keys

key

key_len

ref

rows

Extra

people

ref

fname_lname_age

fname_lname_age

102

const,const,const

1

Where used

下面我們就來看看這個EXPLAIN分析結果的含義。

table:這是表的名字。

type:連接操作的類型。下面是MySQL文檔關於ref連接類型的說明:

「對於每一種與另一個表中記錄的組合,MySQL將從當前的表讀取所有帶有匹配索引值的記錄。如果連接操作只使用鍵的最左前綴,或者如果鍵不是

UNIQUE或PRIMARY

KEY類型(換句話說,如果連接操作不能根據鍵值選擇出唯一行),則MySQL使用ref連接類型。如果連接操作所用的鍵只匹配少量的記錄,則ref是一種好的連接類型。」

在本例中,由於索引不是UNIQUE類型,ref是我們能夠得到的最好連接類型。

如果EXPLAIN顯示連接類型是「ALL」,而且你並不想從表裡面選擇出大多數記錄,那麼MySQL的操作效率將非常低,因為它要掃瞄整個表。你可以加入更多的索引來解決這個問題。預知更多信息,請參見MySQL的手冊說明。

possible_keys:

可能可以利用的索引的名字。這裡的索引名字是創建索引時指定的索引暱稱;如果索引沒有暱稱,則默認顯示的是索引中第一個列的名字(在本例中,它是「firstname」)。默認索引名字的含義往往不是很明顯。

Key:

它顯示了MySQL實際使用的索引的名字。如果它為空(或NULL),則MySQL不使用索引。

key_len:

索引中被使用部分的長度,以字節計。在本例中,key_len是102,其中firstname占50字節,lastname占50字節,age占2字節。如果MySQL只使用索引中的firstname部分,則key_len將是50。

ref:

它顯示的是列的名字(或單詞「const」),MySQL將根據這些列來選擇行。在本例中,MySQL根據三個常量選擇行。

rows:

MySQL所認為的它在找到正確的結果之前必須掃瞄的記錄數。顯然,這裡最理想的數字就是1。

Extra:

這裡可能出現釵h不同的選項,其中大多數將對查詢產生負面影響。在本例中,MySQL只是提醒我們它將用WHERE子句限制搜索結果集。

七、索引的缺點

到目前為止,我們討論的都是索引的優點。事實上,索引也是有缺點的。

首先,索引要佔用磁盤空間。通常情況下,這個問題不是很突出。但是,如果你創建每一種可能列組合的索引,索引文件體積的增長速度將遠遠超過數據文件。如果你有一個很大的表,索引文件的大小可能達到操作系統允釭熙怳j文件限制。

第二,對於需要寫入數據的操作,比如DELETE、UPDATE以及INSERT操作,索引會降低它們的速度。這是因為MySQL不僅要把改動數據寫入數據文件,而且它還要把這些改動寫入索引文件。

AND lastname='Sullivan' ## 考慮使用索引

///

mysql查询性能优化

mysql的优化可以从硬件设备的选择、操作系统、数据库结构设计、SQL查询、应用程序各个方面进行y优化,这里只从数据库的设计及查询语句方面进行优化。

1,创建索引

对于查询占主要的应用来说,索引显得尤为重要。很多时候性能问题很简单的就是因为我们忘了添加索引而造成的,或者说没有添加更为有效的索引导致。如果不加索引的话,那么查找任何哪怕只是一条特定的数据都会进行一次全表扫描,如果一张表的数据量很大而符合条件的结果又很少,那么不加索引会引起致命的性能下降。但是也不是什么情况都非得建索引不可,比如性别可能就只有两个值,建索引不仅没什么优势,还会影响到更新速度,这被称为过度索引。

2,复合索引

比如有一条语句是这样的:select * from users where area='beijing'

and age=22;

如果我们是在area和age上分别创建单个索引的话,由于mysql查询每次只能使用一个索引,所以虽然这样已经相对不做索引时全表扫描提高了很多效率,但是如果在area、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(area,

age,

salary)的复合索引,那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最佳左前缀特性。因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。

3,索引不会包含有NULL值的列

只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。

4,使用短索引

对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的

列,如果在前10 个或20

个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。

5,排序的索引问题

mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order

by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

6,like语句操作

一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like

"%aaa%" 不会使用索引而like "aaa%"可以使用索引。

7,不要在列上进行运算

select * from users where

YEAR(adddate)<2007;将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成select

* from users where adddate

8,不使用NOT IN和<>操作

NOT IN和<>操作都不会使用索引将进行全表扫描。NOT IN可以NOT

EXISTS代替,id<>3则可使用id>3 or id<3来代替。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值