2014-12-08 21 views
0

想象一下,我有一個大型網站的數據庫,該網站有一個名爲「users」的表,其中包含大量記錄。當我執行查詢如SELECT * FROM users WHERE username='John'我的理解是(忽略緩存等)數據庫將導航索引並找到名爲John的用戶。想象一下,這個查詢返回100萬個結果,我只對25歲的約翰用戶感興趣,所以我執行另一個查詢:SELECT * FROM users WHERE username='John' AND age=25'和'和'or'如何在SQL中工作

這是如何工作的?它是否遍歷所有名爲John的用戶,並只查找那些年齡匹配爲25的用戶,還是有更好的方法來做到這一點?我假設這是數據庫和存儲引擎的具體情況,所以我們可以假設我在InnoDB中使用MySQL。

+0

從我所瞭解的情況來看,它會針對每一行都進行比較,而不是針對每個AND/OR條件重新評估...如果您要使用HAVING子句,那將成爲另一個故事 – 2014-12-08 02:30:06

+1

您可以使用查詢計劃器 – 2014-12-08 02:32:20

回答

2

如果你有這樣的查詢:

SELECT * 
FROM users 
WHERE username = 'John' AND age = 25; 

則最佳指標是users(username, age)users(age, username)。有了這個索引,匹配記錄可以通過在索引中查找來找到。

至於如果你只有username索引會發生什麼。它通常會在username列中查找帶有「John」的行。然後,它將從數據頁獲取記錄,並繼續基於頁面上的數據進行過濾。

2

假設您在兩列上都有索引,它通常會檢查數據本身的統計信息以選擇一個儘可能快地減少結果集基數的選項。

例如,如果20%的人是25,但只有3%年齡在被稱爲約翰,它會首先得到約翰然後去掉那些誰不老化25

如果你做了一個組合鍵都是列,那麼這應該會更快,因爲根本沒有「剝離」。底線,它歸結爲數據庫引擎瞭解數據的組成,並基於此選擇最佳執行計劃。這就是爲什麼定期重新計算統計數據通常很好,因爲數據可能會發生變化。

3

答案是 - 你不應該問這個問題。在像SQL這樣的聲明性語言中,您可以描述所需的結果,並且處理引擎將確定產生結果的最佳方式。根據請求中看似微小的差異可能需要不同的路徑才能得出結果,或者所用的方法可能會隨產品版本的變化而變化,甚至可能基於某些與產品完全無關的因素(可用內存或磁盤空間, 例如)。

這就是說,以下是 SQL數據庫的真正在箱子:

  1. 該數據庫將在評估只使用一個索引WHERE子句。
  2. 如果使用多於一個索引可以使用來評估WHERE子句,那麼數據庫將使用每個索引中基數(值的分佈)的統計信息來選擇「最佳」子集。
  3. 如果存在由多個列構建的索引,並且該索引的列存在於WHERE子句的過濾條件中,那麼該索引可以用於過濾多列一個單一的索引。

因此,在您的示例中,大多數數據庫將使用年齡或名稱上的索引來執行第一級過濾,然後掃描結果記錄以執行第二級過濾。唯一的例外是,如果您在(姓名,年齡)或(年齡,姓名)上有複合索引,在這種情況下只需要進行索引掃描即可查找記錄。