sqlforce
A. 如何進行sql性能優化
這里分享下mysql優化的幾種方法。
1、首先在打開的軟體中,需要分別為每一個表創建 InnoDB FILE的文件。
B. 如何解決SQL查詢速度太慢
1. 執行計劃中明明有使用到索引,為什麼執行還是這么慢?
2. 執行計劃中顯示掃描行數為 644,為什麼 slow log 中顯示 100 多萬行?
a. 我們先看執行計劃,選擇的索引 「INDX_BIOM_ELOCK_TASK3(TASK_ID)」。結合 sql 來看,因為有 "ORDER BY TASK_ID DESC" 子句,排序通常很慢,如果使用了文件排序性能會更差,優化器選擇這個索引避免了排序。
那為什麼不選 possible_keys:INDX_BIOM_ELOCK_TASK 呢?原因也很簡單,TASK_DATE 欄位區分度太低了,走這個索引需要掃描的行數很大,而且還要進行額外的排序,優化器綜合判斷代價更大,所以就不選這個索引了。不過如果我們強制選擇這個索引(用 force index 語法),會看到 SQL 執行速度更快少於 10s,那是因為優化器基於代價的原則並不等價於執行速度的快慢;
b. 再看執行計劃中的 type:index,"index" 代表 「全索引掃描」,其實和全表掃描差不多,只是掃描的時候是按照索引次序進行而不是行,主要優點就是避免了排序,但是開銷仍然非常大。
Extra:Using where 也意味著掃描完索引後還需要回表進行篩選。一般來說,得保證 type 至少達到 range 級別,最好能達到 ref。
在第 2 點中提到的「慢日誌記錄Rows_examined: 1161559,看起來是全表掃描」,這里更正為「全索引掃描」,掃描行數確實等於表的行數;
c. 關於執行計劃中:「rows:644」,其實這個只是估算值,並不準確,我們分析慢 SQL 時判斷准確的掃描行數應該以 slow log 中的 Rows_examined 為准。
4. 優化建議:添加組合索引 IDX_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID)
優化過程:
TASK_DATE 欄位存在索引,但是選擇度很低,優化器不會走這個索引,建議後續可以刪除這個索引:
select count(*),count(distinct TASK_DATE) from T_BIOMA_ELOCK_TASK;+------------+---------------------------+| count(*) | count(distinct TASK_DATE) |+------------+---------------------------+| 1161559 | 223 |+------------+---------------------------+
在這個 sql 中 REL_DEVID 欄位從命名上看選擇度較高,通過下面 sql 來檢驗確實如此:
select count(*),count(distinct REL_DEVID) from T_BIOMA_ELOCK_TASK;+----------+---------------------------+| count(*) | count(distinct REL_DEVID) |+----------+---------------------------+| 1161559 | 62235 |+----------+---------------------------+
由於有排序,所以得把 task_id 也加入到新建的索引中,REL_DEVID,task_id 組合選擇度 100%:
select count(*),count(distinct REL_DEVID,task_id) from T_BIOMA_ELOCK_TASK;+----------+-----------------------------------+| count(*) | count(distinct REL_DEVID,task_id) |+----------+-----------------------------------+| 1161559 | 1161559 |+----------+-----------------------------------+
在測試環境添加 REL_DEVID,TASK_ID 組合索引,測試 sql 性能:alter table T_BIOMA_ELOCK_TASK add index idx_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID);
添加索引後執行計劃:
這里還要注意一點「隱式轉換」:REL_DEVID 欄位數據類型為 varchar,需要在 sql 中加引號:AND T.REL_DEVID = 000000025xxx >> AND T.REL_DEVID = '000000025xxx'
執行時間從 10s+ 降到 毫秒級別:
1 row in set (0.00 sec)
結論
一個典型的 order by 查詢的優化,添加更合適的索引可以避免性能問題:執行計劃使用索引並不意味著就能執行快。
C. sql 查詢使用強制索引
使用強制索引的前提是必需有這個索引。你可以在索引里新建一個名稱為f_type的索引 count查詢速度很快的,不建議強制索引;另外,SQL分析器也會對查詢進行優化,所以使用強制索引必要性不大
D. 在SQL中 如何正確使用各種聯接查詢
SELECT--SQL語法
從一個或多個表中檢索數據。SELECT SQL 命令是與其它 Vfp一樣的內置的 Vfp命令。當你使用 SELECT 來生成查詢時, Vfp翻譯查詢並從表中獲取指定數據。你可以從以下地方創建 SELECT 查詢:
「命令」窗口中
帶有其它任何 Vfp命令的 Vfp程序中
查詢設計器中
SELECT [ALL | DISTINCT] [TOP nExpr [PERCENT]] [Alias.] Select_Item
[[AS] Column_Name] [, [Alias.] Select_Item [[AS] Column_Name] ...]
FROM [FORCE] [DatabaseName!] Table [[AS] Local_Alias]
[ [INNER | LEFT [OUTER] | RIGHT [OUTER] | FULL [OUTER] JOIN DatabaseName!]
Table [[AS] Local_Alias] [ON JoinCondition ...]
[[INTO Destination] | [TO FILE FileName [ADDITIVE] | TO PRINTER [PROMPT] | TO SCREEN]]
[PREFERENCE PreferenceName] [NOCONSOLE] [PLAIN] [NOWAIT]
[WHERE JoinCondition [AND JoinCondition ...] [AND | OR FilterCondition [AND | OR FilterCondition ...]]]
[Group By GroupColumn [, GroupColumn ...]] [HAVING FilterCondition] [UNION [ALL] SELECTCommand]
[Order By Order_Item [ASC | DESC] [, Order_Item [ASC | DESC] ...]]
參數
SELECT
在 SELECT 子句中指定在查詢結果中包含的欄位、常量和表達式。
ALL
查詢結果中包含所有行 ( 包括重復值 )。ALL 是默認設置。
DISTINCT
在查詢結果中剔除重復的行。每一個 SELECT 子句只能使用一次 DISTINCT。
TOP nExpr [PERCENT]
在符合查詢條件的所有記錄中,選取指定數量或百分比的記錄。TOP 子句必須與 ORDER BY 子句同時使用。ORDER BY 子句指定查詢結果中包含的列上由Top字句決定的行數, TOP 子句根據此排序選定最開始的 nExpr個或 nExpr% 的記錄。
您可以指定選取 1 到 32767 個記錄。使用 ORDER BY 子句指定的欄位進行排序,會產生並列的情況,比如,可能有多個記錄,它們在選定的欄位上相同;所以,如果您指定 nExpr 為 10,在查詢結果中可能多於 10 個記錄,因為可能有幾個記錄位置並列。
如果包含 PERCENT 關鍵字指定查詢結果中的記錄數,得到記錄數的可能是小數,這時進行取整。包含 PERCENT 關鍵字時,nExpr 的范圍是 0.01 到 99.99。
[Alias.] Select_Item
限定匹配項的名稱。Select_Item 指定的每一項在查詢結果中都生成一列。一個項可以是以下一個
FROM 子句所包含的表中的欄位名稱。
一個常量,查詢結果中每一行都出現這個常量值。
一個表達式,可以是用戶自定義函數名。
關於使用用戶定義函數的詳細信息, 參見注釋節中的帶用戶定義函數的 SELECT。
你用 Select_Item 指定的各項生成一個查詢結果列。
如果兩個或更多的項具有相同的名稱, 在項名前包含表別名和一個句點來避免列重復。
[AS] Column_Name
為查詢輸出中的列指定顯示名。Column_Name 可以是表達式但不能包含不允許的字元, 如, 欄位名中的空格。
當 Select_Item 是一個表達式或包含一個欄位函數而且你想給該列一個有意義的名字時該選項是有用的。
FROM [FORCE] DatabaseName!
列出所有從中檢索數據的表。
FORCE 指定連接表時按它們出現在 FROM 子句中的順序。如果省略 FORCE, Vfp會試圖對查詢進行優化。但是, 使用 FORCE 子句,避免了優化過程,可能加快查詢執行的速度。
當包含表的資料庫不是當前資料庫時,DatabaseName! 指定這個資料庫的名稱。如果資料庫不是當前資料庫,就必須指定包含表的資料庫名稱。應在資料庫名稱之後表名之前加上感嘆號(!)分隔符。
[[AS] Local_Alias]
為 Table 中的表指定一個臨時名稱。如果指定了本地別名,那麼在整個SELECT 語句中必須都用這個別名代替表名。本地別名不影響 Visual FoxPro環境。INNER JOIN 只有在其他表中包含對應記錄(一個或多個)的記錄才出現在查詢結果中。
INNER JOIN 只有在其他表中包含對應記錄(一個或多個)的記錄才出現在查詢結果中。
LEFT [OUTER] JOIN 在查詢結果中包含:JOIN 左側表中的所有記錄,以及JOIN 右側表中匹配的記錄。OUTER 關鍵字可被省略;包含 OUTER 強調這是一個外連接 (outer join)。
RIGHT [OUTER] JOIN 在查詢結果中包含:JOIN 右側表中的所有記錄,以及 JOIN 左側表中匹配的記錄。OUTER 關鍵字可被省略;包含 OUTER 強調這是一個外連接接 (outer join)。
FULL [OUTER] JOIN 在查詢結果中包含:JOIN 兩側所有的匹配記錄,和不匹配的記錄;包含 OUTER 強調這是一個外連接 (outer join)。
關於連接的詳細信息, 參見備注段中的 Joins。
ON JoinCondition 指定連接條件。
INTO Destination
指定在何處保存查詢結果。Destination 可以是下列子句之一:
ARRAY ArrayName ,將查詢結果保存到變數數組中。
如果查詢結果中不包含任何記錄,則不創建這個數組。
CURSOR CursorName [NOFILTER | READWRITE] 將查詢結果保存到臨時表中。
要創建一個查用於子查詢中的游標, 用 NOFILTER。關於 NOFILTER 的詳細信息, 參見備注節。
要指定游標是臨時的和可修改的, 使用 READWRITE。如果源表或表使用 autoincrementing, 該設置不會被 READWRITE 游標繼承。
DBF | TABLE TableName [DATABASE DatabaseName [NAME LongTableName]] 保存查詢結果到一個表中。
包含 DATABASE DatabaseName 以指定添加了表的資料庫。
包含 NAME LongTableName 可以為該表命一個最多可包括 128 個字元的並且可以在資料庫中代替短名字的長名。
如果沒有包括 INTO 子句, 查詢結果顯示在一個「瀏覽」窗口中。也可以用 TO FILE 子句來定向查詢結果到列印機或一個文件。
TO FILE FileName [ADDITIVE] | TO PRINTER [PROMPT] | TO SCREEN
定向查詢結果到列印機或一個文件。
ADDITIVE 添加查詢輸出到 TO FILE FileName 中指定的已存在的文本文件內容中。
TO PRINTER 定向查詢輸出到一個列印機。在列印開始之前,使用可選的 PROMPT 子句顯示一個對話框。您可以根據當前安裝的列印機驅動程序調整列印機的設置。將 PROMPT 子句放置在緊跟 TO PRINTER 之後。
TO SCREEN 使查詢結果定向輸出到 Vfp主窗口或活動的用戶自定義窗口中。
PREFERENCE PreferenceName
如果查詢結果送往瀏覽窗口,就可以使用 PREFERENCE 保存瀏覽窗口的屬性和選項以備後用。關於 PREFERENCE 功能的詳細信息, 參見備注節。
NOCONSOLE
不顯示送到文件、列印機或 Vfp主窗口的查詢結果。
PLAIN
防止列標題出現在顯示的查詢結果中。不管有無 TO 子句都可使用 PLAIN子句。如果 SELECT 語句中包括 INTO 子句,則忽略 PLAIN 子句。
NOWAIT
打開瀏覽窗口並將查詢結果輸出到這個窗口後繼續程序的執行。程序並不等待關閉瀏覽窗口,而是立即執行緊接在 SELECT 語句後面的程序行。關於如何使用 NOWAIT 的說明, 參見備注節。
WHERE JoinCondition
指定 Vfp的查詢結果中只包括符合指定條件的記錄。JoinCondition 指定位於 FROM 子句中的欄位連接表。關於指定連接條件的詳細信息, 參見備注節。
WHERE 支持 JoinCondition 的 ESCAPE 操作符, 讓你可以執行包含有百分號 (%) 和下劃線 (_) 通配符的 SELECT SQL 命令查詢。ESCAPE 允許你指定一個按原字樣處理的 SELECT SQL 命令通配符。在 ESCAPE 子句中, 一旦一個字元被放到通配符字元之前,就表示這個通配符被看作一個文字字元。
FilterCondition
指定將包含在查詢結果中記錄必須符合的條件。使用 AND 或 OR 操作符,您可以包含隨意數目的過濾條件。您還可以使用 NOT 操作符將邏輯表達式的值取反,或使用 EMPTY() 函數以檢查空欄位。
SELECT SQL 命令在篩選條件中支持 "<field> IS / IS NOT NULL"。要學習如何使用 FilterCondition。
Group By GroupColumn [, GroupColumn ...]
按列的值對查詢結果的行進行分組。GroupColumn 可以是常規的表欄位名,也可以是一個包含 SQL 欄位函數的欄位名,還可以是一個數值表達式,指定查詢結果表中的列位置(最左邊的列編號為 1 )。
HAVING FilterCondition
指定包括在查詢結果中的組必須滿足的篩選條件。HAVING 應該同 GROUP BY一起使用。它能包含數量不限的篩選條件,篩選條件用 AND 或 OR 連接,還可以使用 NOT 來對邏輯表達式求反。可以在 HAVING 子句中使用本地別名和欄位函數。 關於你可以使用的欄位函數的詳細信息, 參見備注節。FilterCondition 不能包含子查詢。
可以使用帶 HAVING 子句的 Group By。使用 HAVING 子句的命令如果沒有使用 GROUP BY 子句,則它的作用與WHERE 子句相同。
如果 HAVING 子句不包含欄位函數的話,使用 WHERE 子句可以獲得較快的速度。
HAVING 子句應該出現在 INTO 子句前否則產生錯誤。
[UNION [ALL] SELECTCommand]
把一個 SELECT 語句的最後查詢結果同另一個 SELECT 語句最後查詢結果組合起來。默認情況下,UNION 檢查組合的結果並排除重復的行。
要組合多個UNION 子句,可使用括弧。可以用 UNION 子句模擬一個外部聯接。
ALL 防止 UNION 刪除組合結果中重復的行。
當一個列是備注或通用型時, 不允許連接不同類型的列。
在 Vfp8.0 以前的版本中, 當在兩個不同類型的欄位上執行 UNION 操作時你需要執行明確的轉換。
Vfp現在對支持它的數據類型支持隱含數據類型轉換。關於隱含數據類型轉換和數據類型優先, UNION 子句允許的規則, 以及其它信息的詳細內容, 參見備注節中的數據類型轉換和優先。
Order By Order_Item [ASC | DESC]
根據列的數據對查詢結果進行排序。每個 Order_Item 都必須對應查詢結果中的一列。它可以是下列之一:
FROM 子句中表的欄位,同時也是 SELECT 主句(不在子查詢中)的一個選擇項。
一個數值表達式,表示查詢結果中列的位置(最左邊列編號為 1 )。
ASC 指定查詢結果根據排序項以升序排列。它是 ORDER BY 的默認選項。
DESC 指定查詢結果以降序排列。
備注
在使用 FROM 子句時如果沒有打開表, Vfp顯示「打開」對話框讓你指定文件位置。一但打開後, 表在查詢完成後仍然保持打開。
當在 Destination 參數中使用 CURSOR 子句時, 如果你指定了一個打開的表的名字, Vfp產生一條錯誤信息。在 SELECT 執行後, 臨時游標保持打開並是活動的和只讀的除非你指定了 READWRITE 選項。當你關閉該臨時游標時, 它被刪除。游標可以指定 SORTWORK 而成為存在於驅動器或卷上的臨時文件。
當在 Destination 參數中使用 CURSOR 子句時, 你現在可以使用 NOFILTER 來創建一個可用於後來的查詢的游標。在早期版本的 Vfp中, 你需要包括一個額外的常數或表達式作為篩選。例如, 添加一個邏輯 true 作為篩選表達式來創建一個可用於後來的查詢的查詢:
SELECT *, .T. FROM customers INTO CURSOR myquery
但是, 包括 NOFILTER 會降低查詢性能因為要在磁碟上創建一個臨時表。臨時表在游標關閉時從磁碟上刪除。
當在 Destination 參數中使用 DBF | TABLE 子句時, 如果你指定了一個已經打開的表, 而且 SET SAFETY 是設置為 OFF, Vfp不警告地復寫該表。如果你沒有指定一個擴展名, Vfp給表一個 .dbf 擴展名。在 SELECT 執行後表保持打開並且是活動的。
如果你在相同查詢中包括 INTO 和 TO 子句, Vfp忽略 TO 子句。如果你包括 TO 子句但沒有包括 INTO 子句, 你可以定向查詢結果到一個名為 FileName 的 ASCII 文本文件, 到列印機, 或到 Vfp主窗口。
PREFERENCE 把特徵, 屬性或參數選項長期保存在 FoxUser.dbf 資源文件中。Preferences 可以在任何時候獲取。第一次執行有 PREFERENCE Preference Name 的 SELECT 命令時創建參數選項。以後執行有相同參數選項名的 SELECT 命令時便將瀏覽窗口恢復到原來的參數選項狀態。當瀏覽窗口關閉時,更新參數選項。如果您按下 CTRL+Q+W 鍵退出「瀏覽」窗口,您對「瀏覽」窗口所做的更改不會保存到資源文件中。
SELECT 命令中包括 TO SCREEN 可以把查詢結果定向輸出到 Vfp主窗口或用戶自定義窗口。如果顯示時 Vfp主窗口或用戶自定義窗口中寫滿了一屏,就暫停輸出。按任意鍵可以查看查詢結果後面的內容。但是,如果命令中包括了 NOWAIT 子句,顯示查詢結果時就不會暫停,等待按鍵,而是在 Vfp主窗口或用戶自定義窗口中連續滾過所有內容。如果命令中包含有 INTO 子句,忽略 NOWAIT 子句。
在一個 SQL 查詢的 WHERE 子句中包括 EVALUATE() 函數會返回不正確的數據。
如果包括一個以上的表在查詢中, 你應該在第一個以後為每一個表指定一個連接條件。連接條件可以包含篩選條件。
注意 每一個 SELECT 語句的最大連接數是 9.
必須用 AND 操作符來連接多個連接條件。各連接條件具有以下格式:
當你在串中使用 = 操作符時, 它的動作根據 SET ANSI 的設置會不同。當 SET ANSI 設置為 OFF 時, Vfp只比較串到較短串結束。當 SET ANSI 設置為 ON 時, Vfp遵循 ANSI 標準的字元串比較。關於 Vfp如果執行字元串比較的額外信息, 參見 SET ANSI 和 SET EXACT。
下列欄位函數可以與選定項一起使用,選定項可以是一個欄位或包含欄位的表達式:
AVG(Select_Item), 計算列中數值的平均值。
COUNT(Select_Item), 計算列中選定項的數目。計算查詢輸出的行數。COUNT(*) 計算查詢輸出中的行數。
MIN(Select_Item), 確定列中 Select_Item 的最小值。
MAX(Select_Item), 確定列中 Select_Item 的最大值。
SUM(Select_Item), 計算列中數值的和。
欄位函數不能嵌套使用。
UNION 子句遵守下列規則:
不能使用 UNION 來組合子查詢。
兩個 SELECT 命令的查詢結果中的列數必須相同。
兩個 SELECT 查詢結果中的對應列必須有相同的數據類型和寬度。
只有最後的 SELECT 中可以包含 ORDER BY 子句,而且必須按編號指出所輸出的列。如果包含了一個 ORDER BY 子句,它將影響整個結果。
當你用 UNION 連接查詢中的兩個表時, 僅匹配連接欄位值的記錄會出現在查詢結果中。如果在父表中的記錄在子表中沒有相應的記錄, 父表中的記錄不會出現在查詢結果中。一個外部聯接允許你包括父表中的所有記錄到輸出結果中, 連同子表中的匹配記錄一起。要在 Vfp中創建一個外部聯接, 你需要要使用一個嵌套的 SELECT 命令
注意 確信在每一個分號前包括一個空格。否則, Vfp產生一個錯誤。
上例中, 在 UNION 子句前的部分的命令從兩個表中選擇具有匹配值的記錄。不包括沒有相關的發票的客戶公司。命令中 UNION 子句後的部分選擇客戶表中的在訂單表中無匹配記錄的記錄。
關於第二部分的命令, 注意以下幾點:
包括在園括弧中的 SELECT 語句首先處理。該語句的結果是選擇訂單表中的所有客戶編號。
WHERE 子句找出 customer 表中的在 orders 表沒有相關記錄的所有客戶編號。由於第一節中的命令提供了所在 orders 表中有客戶編號的公司, Customer 表中的所有公司現在都包含在查詢結果中了。
因為在 UNION 中的表的結構必須相同, 有兩個佔位符在第二個 SELECT 語句中來代表第一個 SELECT 語句中的 orders.order_id 和 orders.emp_id。
注意 佔位符必須與它們所代表的欄位有相同類型。如果欄位是日期型, 佔位符應該是 。如果欄位是一個字元欄位, 佔位符應該是一個空串 ("")。
如果你沒有在 Order By 子句中指定排序, 查詢結果顯示為未排序。
當你發出 SET TALK ON 並執行 SELECT 時, Vfp顯示查詢使用的時間和結果中的記錄數。 _TALLY 包含了在查詢結果中的記錄數。
SET FILTER 設置的篩選條件對 SELECT 命令不起作用。
注意 下面部分提到的子查詢, 是指在 SELECT 命令中包含的 SELECT 命令。子查詢必須包括在園括弧中。在 SELECT 命令的 WHERE 子句中可以包含最多兩個平級的(非嵌套)的子查詢。子查詢中可以有多個連接條件 (join conditions)。
在你創建查詢輸出時, 列的命名遵循如下規則:
如果選擇項是具有唯一名稱的欄位,則用欄位名作為輸出列名。
如果多個選擇項具有相同名稱。例如,如果名為 Customer 的表有一個STREET 欄位,而名為 Employees 的表也有一個 STREET 欄位,則輸出列命名為 Extension_A 和 Extension_B (STREET_A 和 STREET_B)。如果選擇項名稱有 10 字元長,可以將名稱截短後再加下劃線和字母。例如,DEPARTMENT 變為 DEPARTME_A。
如果選擇項是表達式,它的輸出列命名為 EXP_A。其他表達式分別命名為EXP_B、EXP_C,依此類推。
如果選擇項包含諸如 COUNT() 這樣的欄位函數,則輸出列命名為CNT_A。如果另一個選擇項包含 SUM(),它的輸出列命名為 SUM_B。
用戶定義函數和 在 SELECT 子句中使用用戶自定義函數有明顯優點,但使用時應考慮以下限制:
SELECT 子句的運行速度會受用戶自定義函數執行速度的影響。因此,如果使用戶自定義函數的操作量很大,則這些函數的功能最好調用 C 語言或匯編語言編寫的 API 或用戶自定義函數來完成。
在 SELECT 激活的用戶自定義函數中,很難預測 Vfp輸入/輸出(I/O)和表的環境。一般來說,不知道選擇的工作區是哪一個,不知道當前表的名稱,甚至不知道正在處理的欄位名。這些變數的值完全取決於用戶自定義函數在優化過程的什麼地方激活。
在 SELECT 子句調用的用戶自定義函數中修改 VfpI/O 或表的環境是很不安全的。一般來說,這樣做的結果難以預料。
從 SELECT 將值傳遞給用戶自定函數唯一可靠的方法,是激活用戶自定義函數時以參數的形式傳遞。
經過實踐,有可能發現某種被認為是違法的操作在某種 FoxPro 版本中運行正確,但這並不保證它在以後的版本中也能正確運行。
拋開這些限制不說,用戶自定義函數在 SELECT 語句中還是可接受的。但不要忘記使用 SELECT 可能要降低性能。要學習如何在 SELECT 中使用用戶定義函數, 參見示例節。
連接 Vfp支持 ANSI SQL '92 連接 (Join) 語法,通過比較兩個或多個表中的欄位,將它們的記錄連接到一起,生成查詢。例如,內部連接 (inner join) 是將兩個表中連接欄位 (joined field) 值相同的記錄選取到查詢中。Vfp支持嵌套連接(nested joins)
由於 SQL 是派生於數學集合理論, 各表可以代表一個環。指定連接條件的 ON 子句確定交接點, 它代表匹配的行集合。對於一個內部聯接, 交接發生在兩個環的內部或 "inner" 部分。一個外聯接不僅僅包括這些表內部的交叉區域匹配的行, 也包括環的外面的左或右部的交集的行。
E. SQL語句執行過程詳解
SQL語句執行過程詳解
一條sql,plsql的執行到底是怎樣執行的呢?
一、SQL語句執行原理:
第一步:客戶端把語句發給伺服器端執行當我們在客戶端執行 select 語句時,客戶端會把這條 SQL 語句發送給伺服器端,讓伺服器端的
進程來處理這語句。也就是說,Oracle 客戶端是不會做任何的操作,他的主要任務就是把客戶端產生
的一些 SQL 語句發送給伺服器端。雖然在客戶端也有一個資料庫進程,但是,這個進程的作用跟伺服器
上的進程作用事不相同的。伺服器上的資料庫進程才會對SQL 語句進行相關的處理。不過,有個問題需
要說明,就是客戶端的進程跟伺服器的進程是一一對應的。也就是說,在客戶端連接上伺服器後,在客戶
端與伺服器端都會形成一個進程,客戶端上的我們叫做客戶端進程;而伺服器上的我們叫做伺服器進程。
第二步:語句解析
當客戶端把 SQL 語句傳送到伺服器後,伺服器進程會對該語句進行解析。同理,這個解析的工作,
也是在伺服器端所進行的。雖然這只是一個解析的動作,但是,其會做很多「小動作」。
1. 查詢高速緩存(library cache)。伺服器進程在接到客戶端傳送過來的 SQL 語句時,不
會直接去資料庫查詢。而是會先在資料庫的高速緩存中去查找,是否存在相同語句的執行計劃。如果在
數據高速緩存中,則伺服器進程就會直接執行這個 SQL 語句,省去後續的工作。所以,採用高速數據緩
存的話,可以提高 SQL 語句的查詢效率。一方面是從內存中讀取數據要比從硬碟中的數據文件中讀取
數據效率要高,另一方面,也是因為這個語句解析的原因。
不過這里要注意一點,這個數據緩存跟有些客戶端軟體的數據緩存是兩碼事。有些客戶端軟體為了
提高查詢效率,會在應用軟體的客戶端設置數據緩存。由於這些數據緩存的存在,可以提高客戶端應用軟
件的查詢效率。但是,若其他人在伺服器進行了相關的修改,由於應用軟體數據緩存的存在,導致修改的
數據不能及時反映到客戶端上。從這也可以看出,應用軟體的數據緩存跟資料庫伺服器的高速數據緩存
不是一碼事。
2. 語句合法性檢查(data dict cache)。當在高速緩存中找不到對應的 SQL 語句時,則服
務器進程就會開始檢查這條語句的合法性。這里主要是對 SQL 語句的語法進行檢查,看看其是否合乎
語法規則。如果伺服器進程認為這條 SQL 語句不符合語法規則的時候,就會把這個錯誤信息,反饋給客
戶端。在這個語法檢查的過程中,不會對 SQL 語句中所包含的表名、列名等等進行 SQL 他只是語法
上的檢查。
3. 語言含義檢查(data dict cache)。若 SQL 語句符合語法上的定義的話,則伺服器進程
接下去會對語句中的欄位、表等內容進行檢查。看看這些欄位、表是否在資料庫中。如果表名與列名不
准確的話,則資料庫會就會反饋錯誤信息給客戶端。所以,有時候我們寫 select 語句的時候,若語法
與表名或者列名同時寫錯的話,則系統是先提示說語法錯誤,等到語法完全正確後,再提示說列名或表名
錯誤。
4. 獲得對象解析鎖(control structer)。當語法、語義都正確後,系統就會對我們需要查詢
的對象加鎖。這主要是為了保障數據的一致性,防止我們在查詢的過程中,其他用戶對這個對象的結構發
生改變。
5. 數據訪問許可權的核對(data dict cache)。當語法、語義通過檢查之後,客戶端還不一定
能夠取得數據。伺服器進程還會檢查,你所連接的用戶是否有這個數據訪問的許可權。若你連接上伺服器
的用戶不具有數據訪問許可權的話,則客戶端就不能夠取得這些數據。有時候我們查詢數據的時候,辛辛苦
苦地把 SQL 語句寫好、編譯通過,但是,最後系統返回個 「沒有許可權訪問數據」的錯誤信息,讓我們氣
半死。這在前端應用軟體開發調試的過程中,可能會碰到。所以,要注意這個問題,資料庫伺服器進程先
檢查語法與語義,然後才會檢查訪問許可權。
6. 確定最佳執行計劃 ?。當語句與語法都沒有問題,許可權也匹配的話,伺服器進程還是不會直接對
資料庫文件進行查詢。伺服器進程會根據一定的規則,對這條語句進行優化。不過要注意,這個優化是有
限的。一般在應用軟體開發的過程中,需要對資料庫的 sql 語言進行優化,這個優化的作用要大大地大
於伺服器進程的自我優化。所以,一般在應用軟體開發的時候,資料庫的優化是少不了的。當伺服器進程
的優化器確定這條查詢語句的最佳執行計劃後,就會將這條 SQL 語句與執行計劃保存到數據高速緩存
(library cache)。如此的話,等以後還有這個查詢時,就會省略以上的語法、語義與許可權檢查的步驟,
而直接執行 SQL 語句,提高 SQL 語句處理效率。
第三步:語句執行
語句解析只是對 SQL 語句的語法進行解析,以確保伺服器能夠知道這條語句到底表達的是什麼意
思。等到語句解析完成之後,資料庫伺服器進程才會真正的執行這條 SQL 語句。這個語句執行也分兩
種情況。
一是若被選擇行所在的數據塊已經被讀取到數據緩沖區的話,則伺服器進程會直接把這個數據傳遞
給客戶端,而不是從資料庫文件中去查詢數據。
若數據不在緩沖區中,則伺服器進程將從資料庫文件中查詢相關數據,並把這些數據放入到數據緩沖
區中(buffer cache)。
第四步:提取數據
當語句執行完成之後,查詢到的數據還是在伺服器進程中,還沒有被傳送到客戶端的用戶進程。所以,
在伺服器端的進程中,有一個專門負責數據提取的一段代碼。他的作用就是把查詢到的數據結果返回給
用戶端進程,從而完成整個查詢動作。從這整個查詢處理過程中,我們在資料庫開發或者應用軟體開發過
程中,需要注意以下幾點:
一是要了解資料庫緩存跟應用軟體緩存是兩碼事情。資料庫緩存只有在資料庫伺服器端才存在,在
客戶端是不存在的。只有如此,才能夠保證資料庫緩存中的內容跟資料庫文件的內容一致。才能夠根據
相關的規則,防止數據臟讀、錯讀的發生。而應用軟體所涉及的數據緩存,由於跟資料庫緩存不是一碼事
情,所以,應用軟體的數據緩存雖然可以提高數據的查詢效率,但是,卻打破了數據一致性的要求,有時候
會發生臟讀、錯讀等情況的發生。所以,有時候,在應用軟體上有專門一個功能,用來在必要的時候清除
數據緩存。不過,這個數據緩存的清除,也只是清除本機上的數據緩存,或者說,只是清除這個應用程序
的數據緩存,而不會清除資料庫的數據緩存。
二是絕大部分 SQL 語句都是按照這個處理過程處理的。我們 DBA 或者基於 Oracle 資料庫的
開發人員了解這些語句的處理過程,對於我們進行涉及到 SQL 語句的開發與調試,是非常有幫助的。有
時候,掌握這些處理原則,可以減少我們排錯的時間。特別要注意,資料庫是把數據查詢許可權的審查放在
語法語義的後面進行檢查的。所以,有時會若光用資料庫的許可權控制原則,可能還不能滿足應用軟體許可權
控制的需要。此時,就需要應用軟體的前台設置,實現許可權管理的要求。而且,有時應用資料庫的許可權管
理,也有點顯得繁瑣,會增加伺服器處理的工作量。因此,對於記錄、欄位等的查詢許可權控制,大部分程
序涉及人員喜歡在應用程序中實現,而不是在資料庫上實現。
DBCC DROPCLEANBUFFERS
從緩沖池中刪除所有清除緩沖區。
DBCC FREEPROCCACHE
從過程緩存中刪除所有元素。
DBCC FREESYSTEMCACHE
從所有緩存中釋放所有未使用的緩存條目
SQL語句中的函數、關鍵字、排序等執行順序:
1. FROM 子句返回初始結果集。
2. WHERE 子句排除不滿足搜索條件的行。
3. GROUP BY 子句將選定的行收集到 GROUP BY 子句中各個唯一值的組中。
4. 選擇列表中指定的聚合函數可以計算各組的匯總值。
5. 此外,HAVING 子句排除不滿足搜索條件的行。
6. 計算所有的表達式;
7. 使用 order by 對結果集進行排序。
8. 查找你要搜索的欄位。
二、SQL語句執行完整過程:
1.用戶進程提交一個 sql 語句:
update temp set a=a*2,給伺服器進程。
2.伺服器進程從用戶進程把信息接收到後,在 PGA 中就要此進程分配所需內存,存儲相關的信息,如在會
話內存存儲相關的登錄信息等。
3.伺服器進程把這個 sql 語句的字元轉化為 ASCII 等效數字碼,接著這個 ASCII 碼被傳遞給一個
HASH 函數,並返回一個 hash 值,然後伺服器進程將到shared pool 中的 library cache 中去查找是否存在相
同的 hash 值,如果存在,伺服器進程將使用這條語句已高速緩存在 SHARED POOL 的library cache 中的已
分析過的版本來執行。
4.如果不存在,伺服器進程將在 CGA 中,配合 UGA 內容對 sql,進行語法分析,首先檢查語法的正確性,接
著對語句中涉及的表,索引,視圖等對象進行解析,並對照數據字典檢查這些對象的名稱以及相關結構,並根據
ORACLE 選用的優化模式以及數據字典中是否存在相應對象的統計數據和是否使用了存儲大綱來生成一個
執行計劃或從存儲大綱中選用一個執行計劃,然後再用數據字典核對此用戶對相應對象的執行許可權,最後生成
一個編譯代碼。
5.ORACLE 將這條 sql 語句的本身實際文本、HASH 值、編譯代碼、與此語名相關聯的任何統計數據
和該語句的執行計劃緩存在 SHARED POOL 的 library cache中。伺服器進程通過 SHARED POOL 鎖存
器(shared pool latch)來申請可以向哪些共享 PL/SQL 區中緩存這此內容,也就是說被SHARED POOL 鎖存
器鎖定的 PL/SQL 區中的塊不可被覆蓋,因為這些塊可能被其它進程所使用。
6.在 SQL 分析階段將用到 LIBRARY
CACHE,從數據字典中核對表、視圖等結構的時候,需要將數據
字典從磁碟讀入 LIBRARY
CACHE,因此,在讀入之前也要使用LIBRARY
CACHE 鎖存器(library cache
pin,library cache lock)來申請用於緩存數據字典。 到現在為止,這個 sql 語句已經被編譯成可執行的代碼了,
但還不知道要操作哪些數據,所以伺服器進程還要為這個 sql 准備預處理數據。
7.首先伺服器進程要判斷所需數據是否在 db buffer 存在,如果存在且可用,則直接獲取該數據,同時根據
LRU 演算法增加其訪問計數;如果 buffer 不存在所需數據,則要從數據文件上讀取首先伺服器進程將在表頭部
請求 TM 鎖(保證此事務執行過程其他用戶不能修改表的結構),如果成功加 TM 鎖,再請求一些行級鎖(TX
鎖),如果 TM、TX 鎖都成功加鎖,那麼才開始從數據文件讀數據,在讀數據之前,要先為讀取的文件准備好
buffer 空間。伺服器進程需要掃面 LRU list 尋找 free db buffer,掃描的過程中,伺服器進程會把發現的所有
已經被修改過的 db buffer 注冊到 dirty list 中, 這些 dirty buffer 會通過 dbwr 的觸發條件,隨後會被寫出到
數據文件,找到了足夠的空閑 buffer,就可以把請求的數據行所在的數據塊放入到 db buffer 的空閑區域或者
覆蓋已經被擠出 LRU list 的非臟數據塊緩沖區,並排列在 LRU list 的頭部,也就是在數據塊放入 DB
BUFFER 之前也是要先申請 db buffer 中的鎖存器,成功加鎖後,才能讀數據到 db buffer。
8.記日誌 現在數據已經被讀入到 db buffer 了,現在伺服器進程將該語句所影響的並被讀
入 db buffer 中的這些行數據的 rowid 及要更新的原值和新值及 scn 等信息從 PGA 逐條的寫入 redo log
buffer 中。在寫入 redo log buffer 之前也要事先請求 redo log buffer 的鎖存器,成功加鎖後才開始寫入,當
寫入達到 redo log buffer 大小的三分之一或寫入量達到 1M 或超過三秒後或發生檢查點時或者 dbwr 之前
發生,都會觸發 lgwr 進程把 redo log buffer 的數據寫入磁碟上的 redo file 文件中(這個時候會產生log file
sync 等待事件)
已經被寫入 redofile 的 redo log buffer 所持有的鎖存器會被釋放,並可被後來的寫入信息覆蓋,
redo log buffer是循環使用的。Redo file 也是循環使用的,當一個 redo file 寫滿後,lgwr 進程會自動切換到
下一 redo file(這個時候可能出現 log fileswitch(checkpoint complete)等待事件)。如果是歸檔模式,歸檔進
程還要將前一個寫滿的 redo file 文件的內容寫到歸檔日誌文件中(這個時候可能出現 log file
switch(archiving needed)。
9.為事務建立回滾段 在完成本事務所有相關的 redo log buffer 之後,伺服器進程開始改寫這個 db buffer
的塊頭部事務列表並寫入 scn,然後 包含這個塊的頭部事務列表及 scn 信息的數據副本放入回滾段中,將
這時回滾段中的信息稱為數據塊的「前映像「,這個」前映像「用於以後的回滾、恢復和一致性讀。(回滾段可以
存儲在專門的回滾表空間中,這個表空間由一個或多個物理文件組成,並專用於回滾表空間,回滾段也可在其它
表空間中的數據文件中開辟。
10.本事務修改數據塊 准備工作都已經做好了,現在可以改寫 db buffer 塊的數據內容了,並在塊的頭部寫
入回滾段的地址。
11.放入 dirty list 如果一個行數據多次 update 而未 commit,則在回滾段中將會有多個「前映像「,除了第
一個」前映像「含有 scn 信息外,其他每個「前映像「的頭部都有 scn 信息和「前前映像」回滾段地址。一個
update 只對應一個 scn,然後伺服器進程將在 dirty list 中建立一
條指向此 db buffer 塊的指針(方便 dbwr 進程可以找到 dirty list 的 db buffer 數據塊並寫入數據文件中)。
接著伺服器進程會從數據文件中繼續讀入第二個數據塊,重復前一數據塊的動作,數據塊的讀入、記日誌、建
立回滾段、修改數據塊、放入 dirty list。當 dirty queue 的長度達到閥值(一般是 25%),伺服器進程將通知
dbwr 把臟數據寫出,就是釋放 db buffer 上的鎖存器,騰出更多的 free db buffer。前面一直都是在說明
oracle 一次讀一個數據塊,其實 oracle 可以一次讀入多個數據塊(db_file_multiblock_read_count 來設置一
次讀入塊的個數)
說明:
在預處理的數據已經緩存在 db buffer 或剛剛被從數據文件讀入到 db buffer 中,就要根據 sql 語句
的類型來決定接下來如何操作。
1>如果是 select 語句,則要查看 db buffer 塊的頭部是否有事務,如果有事務,則從回滾段中讀取數據;如
果沒有事務,則比較 select 的 scn 和 db buffer 塊頭部的 scn,如果前者小於後者,仍然要從回滾段中讀取數據;
如果前者大於後者,說明這是一非臟緩存,可以直接讀取這個 db buffer 塊的中內容。
2>如果是 DML 操作,則即使在 db buffer 中找到一個沒有事務,而且 SCN 比自己小的非臟
緩存數據塊,伺服器進程仍然要到表的頭部對這條記錄申請加鎖,加鎖成功才能進行後續動作,如果不成功,則要
等待前面的進程解鎖後才能進行動作(這個時候阻塞是 tx 鎖阻塞)。
用戶 commit 或 rollback 到現在為止,數據已經在 db buffer 或數據文件中修改完
成,但是否要永久寫到數文件中,要由用戶來決定 commit(保存更改到數據文件) rollback 撤銷數據的更改)。
1.用戶執行 commit 命令
只有當 sql 語句所影響的所有行所在的最後一個塊被讀入 db buffer 並且重做信息被寫入 redo log
buffer(僅指日誌緩沖區,而不包括日誌文件)之後,用戶才可以發去 commit 命令,commit 觸發 lgwr 進程,但不
強制立即 dbwr來釋放所有相應 db buffer 塊的鎖(也就是no-force-at-commit,即提交不強制寫),也就是說有
可能雖然已經 commit 了,但在隨後的一段時間內 dbwr 還在寫這條 sql 語句所涉及的數據塊。表頭部的行鎖
並不在 commit 之後立即釋放,而是要等 dbwr 進程完成之後才釋放,這就可能會出現一個用戶請求另一用戶
已經 commit 的資源不成功的現象。
A .從 Commit 和 dbwr 進程結束之間的時間很短,如果恰巧在 commit 之後,dbwr 未結束之前斷電,因為
commit 之後的數據已經屬於數據文件的內容,但這部分文件沒有完全寫入到數據文件中。所以需要前滾。由
於 commit 已經觸發 lgwr,這些所有未來得及寫入數據文件的更改會在實例重啟後,由 smon 進程根據重做日
志文件來前滾,完成之前 commit 未完成的工作(即把更改寫入數據文件)。
B.如果未 commit 就斷電了,因為數據已經在 db buffer 更改了,沒有 commit,說明這部分數據不屬於數
據文件,由於 dbwr 之前觸發 lgwr 也就是只要數據更改,(肯定要先有 log) 所有 DBWR,在數據文件上的修改
都會被先一步記入重做日誌文件,實例重啟後,SMON 進程再根據重做日誌文件來回滾。
其實 smon 的前滾回滾是根據檢查點來完成的,當一個全部檢查點發生的時候,首先讓 LGWR 進程將
redo log buffer 中的所有緩沖(包含未提交的重做信息)寫入重做日誌文件,然後讓 dbwr 進程將 db buffer 已
提交的緩沖寫入數據文件(不強制寫未提交的)。然後更新控制文件和數據文件頭部的 SCN,表明當前資料庫
是一致的,在相鄰的兩個檢查點之間有很多事務,有提交和未提交的。
像前面的前滾回滾比較完整的說法是如下的說明:
A.發生檢查點之前斷電,並且當時有一個未提交的改變正在進行,實例重啟之後,SMON 進程將從上一個
檢查點開始核對這個檢查點之後記錄在重做日誌文件中已提交的和未提交改變,因為
dbwr 之前會觸發 lgwr,所以 dbwr 對數據文件的修改一定會被先記錄在重做日誌文件中。因此,斷電前被
DBWN 寫進數據文件的改變將通過重做日誌文件中的記錄進行還原,叫做回滾,
B. 如果斷電時有一個已提交,但 dbwr 動作還沒有完全完成的改變存在,因為已經提交,提交會觸發 lgwr
進程,所以不管 dbwr 動作是否已完成,該語句將要影響的行及其產生的結果一定已經記錄在重做日誌文件中
了,則實例重啟後,SMON 進程根據重做日誌文件進行前滾.
實例失敗後用於恢復的時間由兩個檢查點之間的間隔大小來決定,可以通個四個參數設置檢查點執行的頻
率:
Log_checkpoint_interval:
決定兩個檢查點之間寫入重做日誌文件的系統物理塊(redo blocks)
的大小,默認值是 0,無限制。
log_checkpoint_timeout:
兩 個 檢 查 點 之 間 的 時 間 長 度(秒)默 認 值 1800s。
fast_start_io_target:
決定了用於恢復時需要處理的塊的多少,默認值是 0,無限制。
fast_start_mttr_target:
直接決定了用於恢復的時間的長短,默認值是 0,無限制(SMON 進程執行的前滾
和回滾與用戶的回滾是不同的,SMON 是根據重做日誌文件進行前滾或回滾,而用戶的回滾一定是根據回滾段
的內容進行回滾的。
在這里要說一下回滾段存儲的數據,假如是 delete 操作,則回滾段將會記錄整個行的數據,假如是 update,
則回滾段只記錄被修改了的欄位的變化前的數據(前映像),也就是沒有被修改的欄位是不會被記錄的,假如是
insert,則回滾段只記錄插入記錄的 rowid。 這樣假如事務提交,那回滾段中簡單標記該事務已經提交;假如是
回退,則如果操作是 delete,回退的時候把回滾段中數據重新寫回數據塊,操作如果是 update,則把變化前數據
修改回去,操作如果是 insert,則根據記錄的 rowid 把該記錄刪除。
2.如果用戶 rollback。
則伺服器進程會根據數據文件塊和 DB BUFFER 中塊的頭部的事務列表和 SCN 以及回滾段地址找到
回滾段中相應的修改前的副本,並且用這些原值來還原當前數據文件中已修改但未提交的改變。如果有多個
「前映像」,伺服器進程會在一個「前映像」的頭部找到「前前映像」的回滾段地址,一直找到同一事務下的最早的
一個「前映像」為止。一旦發出了 COMMIT,用戶就不能rollback,這使得 COMMIT 後 DBWR 進程還沒有
全部完成的後續動作得到了保障。到現在為例一個事務已經結束了。
說明:
TM 鎖:
符合 lock 機制的,用於保護對象的定義不被修改。 TX 鎖:
這個鎖代表一個事務,是行
級鎖,用數據塊頭、數據記錄頭的一些欄位表示,也是符合 lock 機制,有 resource structure、lock
structure、enqueue 演算法。
F. SQL清除語句
CREATE SNAPSHOT [schema.]snapshot
[ [PCTFREE integer] [PCTUSED integer]
[INITRANS integer] [MAXTRANS integer]
[TABLESPACE tablespace]
[STORAGE storage_clause]
[ USING INDEX [ PCTFREE integer | TABLESPACE tablespace
| INITTRANS integer | MAXTRANS integer
| STORAGE storage_clause ] ...
| [CLUSTER cluster (column [, column]...)] ]
[ REFRESH [FAST | COMPLETE | FORCE] [START WITH date] [NEXT date]]
AS subquery
schema
is the schema to contain the snapshot. If you omit schema, Oracle
creates the snapshot in your schema.
snapshot
is the name of the snapshot to be created.
Oracle chooses names for the table, views, and index used to
maintain the snapshot by prefixing the snapshot name. To limit
these names to 30 bytes and allow them to contain the entire
snapshot name, Oracle Corporation recommends that you limit your
snapshot names to 23 bytes.
PCTFREE
PCTUSED
INITRANS
MAXTRANS
establishes values for these parameters for the internal table
Oracle uses to maintain the snapshot's data.
TABLESPACE
specifies the tablespace in which the snapshot is to be created. If
you omit this option, Oracle creates the snapshot in the default
tablespace of the owner of the snapshot's schema.
STORAGE
establishes storage characteristics for the table Oracle uses to
maintain the snapshot's data.
USING INDEX
specifies the storage characteristics for the index on a simple
snapshot. If the USING INDEX clause not specified, the index is
create with the same tablespace and storage parameters as the
snapshot.
CLUSTER
creates the snapshot as part of the specified cluster. Since a
clustered snapshot uses the cluster's space allocation, do not use
the PCTFREE, PCTUSED, INITRANS, or MAXTRANS parameters, the
TABLESPACE option, or the STORAGE clause in conjunction with the
CLUSTER option.
REFRESH
specifies how and when Oracle automatically refreshes the snapshot:
FAST
specifies a fast refresh, or a refresh using only the
updated data stored in the snapshot log associated
with the master table.
COMPLETE
specifies a complete refresh, or a refresh that re-
executes the snapshot's query.
FORCE
specifies a fast refresh if one is possible or
complete refresh if a fast refresh is not possible.
Oracle decides whether a fast refresh is possible at
refresh time.
If you omit the FAST, COMPLETE, and FORCE options,
Oracle uses FORCE by default.
START WITH
specifies a date expression for the first automatic
refresh time.
NEXT
specifies a date expression for calculating the
interval between automatic refreshes.
Both the START WITH and NEXT values must evaluate to a time in the
future. If you omit the START WITH value, Oracle determines the
first automatic refresh time by evaluating the NEXT expression when
you create the snapshot. If you specify a START WITH value but omit
the NEXT value, Oracle refreshes the snapshot only once. If you
omit both the START WITH and NEXT values or if you omit the REFRESH
clause entirely, Oracle does not automatically refresh the snapshot.
AS subquery
specifies the snapshot query. When you create the snapshot, Oracle
executes this query and places the results in the snapshot. The
select list can contain up to 253 expressions. A snapshot query is
subject to the same restrictions as a view query.
PREREQUISITES:
To create a snapshot in your own schema, you must have CREATE
SNAPSHOT system privilege. To create a snapshot in another user's
schema, you must have CREATE ANY SNAPSHOT system privilege.
Before a snapshot can be created, the user SYS must run the SQL
script DBMSSNAP.SQL on both the database to contain the snapshot and
the database(s) containing the tables and views of the snapshot's
query. This script creates the package SNAPSHOT which contains both
public and private stored proceres used for refreshing the
snapshot and purging the snapshot log. The exact name and location
of this script may vary depending on your operating system.
When you create a snapshot, Oracle creates a table, two views, and
an index in the schema of the snapshot. Oracle uses these objects
to maintain the snapshot's data. You must have the privileges
necessary to create these objects. For information on these
privileges, see the CREATE TABLE, CREATE VIEW, and CREATE INDEX
commands.
The owner of the schema containing the snapshot must have either
space quota on the tablespace to contain the snapshot or UNLIMITED
TABLESPACE system privilege. Also, both you (the creator) and the
owner must also have the privileges necessary to issue the
snapshot's query.
To create a snapshot, you must be using Oracle with the proceral
option. To create a snapshot on a remote table or view, you must
also be using the distributed option.
G. mysql force index 簡單使用
explain sql語句 會返回mysql查詢優化器對將要執行的sql的執行計劃(不是真的執行,只是給出執行計劃)
結果中的possible_keys給出可能使用的索引,
mysql會選擇它認為最合適的索引,有時候mysql認為的最優的索引並不是實際上真的的最快的索引
此時可以用force index人為指定索引
force index 跟著表明後面,用於強制使用指定的索引名(key)
H. SQL 語句執行感覺很慢,怎麼回事
到這個數量級的全部更新,肯定會很慢。
第一。你的記錄不一定在同一個partition,
第二。不明白為什麼那麼多人建議你建索引,你建的索引越多,你的更新速度越慢,因為你更新記錄的同時,還有更新索引。
第三。你必須知道更新速度慢的瓶頸在哪裡。是讀寫太多,還是內存不夠,還是CUP不夠快,然後對症下葯。
下面介紹兩個簡單的辦法,也許有效:
第一:
把這個100W行的表縱向劈成兩個,用外鍵關系連接,一個裝小的,經常改變的數據比如ID,外鍵,狀態值,時間等,另一個裝大的,不經常改變的數據,比如很長的字元串,xml,text 等。
這樣更新時操作小的這個表,可以大大節約內存和CPU 開銷,降低磁碟操作。
壞處就是查詢時會慢些。
第二:
把這100W行橫向切成很多個表,比如每個月的記錄裝在一個表裡,這樣每個表的記錄數可能只有幾萬,查詢,更新都會快很多。
壞處是查詢,更新都不如原來好寫。
I. sql中怎麼停止正在使用的資料庫
請問是什麼資料庫??db2的話可以切換至實例用戶,使用db2stop
force來停止正在使用的資料庫,再使用db2start開啟資料庫。