『壹』 有沒有免費的分析sql性能的小工具
你是說分析語句嗎,那與具體的表結構有關,一般的資料庫本身都要提供這樣的工具,比如informix資料庫是set explain on之後運行sql語句的性能分析都會生成到一個文本文件裡面,而mysql資料庫提供了explain SQL語句的方式查看此語句的性能,從explain的分析結果可以很直觀的看出這個語句的性能,並能由此優化資料庫或者改變語句。
『貳』 sql有類似mysql的explain命令嗎
explain plan、dbms_xplan、sql_trace
『叄』 SQL,索引的例子
就用 mysql 資料庫舉例吧
一、什麼是索引?
索引用來快速地尋找那些具有特定值的記錄,所有MySQL索引都以B-樹的形式保存。如果沒有索引,執行查詢時MySQL必須從第一個記錄開始掃描整個表的所有記錄,直至找到符合要求的記錄。表裡面的記錄數量越多,這個操作的代價就越高。如果作為搜索條件的列上已經創建了索引,MySQL無需掃描任何記錄即可迅速得到目標記錄所在的位置。如果表有1000個記錄,通過索引查找記錄至少要比順序掃描記錄快100倍。
假設我們創建了一個名為people的表:
CREATE TABLE people ( peopleid SMALLINT NOT NULL, name CHAR(50) NOT NULL );
然後,我們完全隨機把1000個不同name值插入到people表。下圖顯示了people表所在數據文件的一小部分:
可以看到,在數據文件中name列沒有任何明確的次序。如果我們創建了name列的索引,MySQL將在索引中排序name列:
對於索引中的每一項,MySQL在內部為它保存一個數據文件中實際記錄所在位置的「指針」。因此,如果我們要查找name等於「Mike」記錄的peopleid(SQL命令為「SELECT peopleid FROM people WHERE name=\'Mike\';」),MySQL能夠在name的索引中查找「Mike」值,然後直接轉到數據文件中相應的行,准確地返回該行的peopleid(999)。在這個過程中,MySQL只需處理一個行就可以返回結果。如果沒有「name」列的索引,MySQL要掃描數據文件中的所有記錄,即1000個記錄!顯然,需要MySQL處理的記錄數量越少,則它完成任務的速度就越快。
二、索引的類型
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表:
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索引:
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:
這里可能出現許多不同的選項,其中大多數將對查詢產生負面影響。在本例中,MySQL只是提醒我們它將用WHERE子句限制搜索結果集。
七、索引的缺點
到目前為止,我們討論的都是索引的優點。事實上,索引也是有缺點的。
首先,索引要佔用磁碟空間。通常情況下,這個問題不是很突出。但是,如果你創建每一種可能列組合的索引,索引文件體積的增長速度將遠遠超過數據文件。如果你有一個很大的表,索引文件的大小可能達到操作系統允許的最大文件限制。
第二,對於需要寫入數據的操作,比如DELETE、UPDATE以及INSERT操作,索引會降低它們的速度。這是因為MySQL不僅要把改動數據寫入數據文件,而且它還要把這些改動寫入索引文件。
【結束語】
在大型資料庫中,索引是提高速度的一個關鍵因素。不管表的結構是多麼簡單,一次500000行的表掃描操作無論如何不會快。如果你的網站上也有這種大規模的表,那麼你確實應該花些時間去分析可以採用哪些索引,並考慮是否可以改寫查詢以優化應用。要了解更多信息,請參見MySQL manual。另外注意,本文假定你所使用的MySQL是3.23版,部分查詢不能在3.22版MySQL上執行。
『肆』 在php裡面如何執行mysql的非查詢語句
看看php手冊吧:mysql_query() 僅對 SELECT,SHOW,EXPLAIN 或 DESCRIBE 語句返回一個資源標識符,如果查詢執行不正確則返回 FALSE。對於其它類型的 SQL 語句,mysql_query() 在執行成功時返回 TRUE,出錯時返回 FALSE。非 FALSE 的返回值意味著查詢是合法的並能夠被伺服器執行。這並不說明任何有關影響到的或返回的行數。 很有可能一條查詢執行成功了但並未影響到或並未返回任何行。
『伍』 資料庫性能優化有哪些措施
1、調整數據結構的設計。這一部分在開發信息系統之前完成,程序員需要考慮是否使用ORACLE資料庫的分區功能,對於經常訪問的資料庫表是否需要建立索引等。
2、調整應用程序結構設計。這一部分也是在開發信息系統之前完成,程序員在這一步需要考慮應用程序使用什麼樣的體系結構,是使用傳統的Client/Server兩層體系結構,還是使用Browser/Web/Database的三層體系結構。不同的應用程序體系結構要求的資料庫資源是不同的。
3、調整資料庫SQL語句。應用程序的執行最終將歸結為資料庫中的SQL語句執行,因此SQL語句的執行效率最終決定了ORACLE資料庫的性能。ORACLE公司推薦使用ORACLE語句優化器(Oracle Optimizer)和行鎖管理器(row-level manager)來調整優化SQL語句。
4、調整伺服器內存分配。內存分配是在信息系統運行過程中優化配置的,資料庫管理員可以根據資料庫運行狀況調整資料庫系統全局區(SGA區)的數據緩沖區、日誌緩沖區和共享池的大小;還可以調整程序全局區(PGA區)的大小。需要注意的是,SGA區不是越大越好,SGA區過大會佔用操作系統使用的內存而引起虛擬內存的頁面交換,這樣反而會降低系統。
5、調整硬碟I/O,這一步是在信息系統開發之前完成的。資料庫管理員可以將組成同一個表空間的數據文件放在不同的硬碟上,做到硬碟之間I/O負載均衡。
6、調整操作系統參數,例如:運行在UNIX操作系統上的ORACLE資料庫,可以調整UNIX數據緩沖池的大小,每個進程所能使用的內存大小等參數。
資料庫(Database)是按照數據結構來組織、存儲和管理數據的倉庫,它產生於距今六十多年前,隨著信息技術和市場的發展,特別是二十世紀九十年代以後,數據管理不再僅僅是存儲和管理數據,而轉變成用戶所需要的各種數據管理的方式。資料庫有很多種類型,從最簡單的存儲有各種數據的表格到能夠進行海量數據存儲的大型資料庫系統都在各個方面得到了廣泛的應用。
在信息化社會,充分有效地管理和利用各類信息資源,是進行科學研究和決策管理的前提條件。資料庫技術是管理信息系統、辦公自動化系統、決策支持系統等各類信息系統的核心部分,是進行科學研究和決策管理的重要技術手段。
在經濟管理的日常工作中,常常需要把某些相關的數據放進這樣的「倉庫」,並根據管理的需要進行相應的處理。
例如,企業或事業單位的人事部門常常要把本單位職工的基本情況(職工號、姓名、年齡、性別、籍貫、工資、簡歷等)存放在表中,這張表就可以看成是一個資料庫。有了這個"數據倉庫"我們就可以根據需要隨時查詢某職工的基本情況,也可以查詢工資在某個范圍內的職工人數等等。這些工作如果都能在計算機上自動進行,那我們的人事管理就可以達到極高的水平。此外,在財務管理、倉庫管理、生產管理中也需要建立眾多的這種"資料庫",使其可以利用計算機實現財務、倉庫、生產的自動化管理。
(5)sqlserverexplain擴展閱讀
資料庫,簡單來說是本身可視為電子化的文件櫃--存儲電子文件的處所,用戶可以對文件中的數據進行新增、截取、更新、刪除等操作。
資料庫指的是以一定方式儲存在一起、能為多個用戶共享、具有盡可能小的冗餘度的特點、是與應用程序彼此獨立的數據集合。
在經濟管理的日常工作中,常常需要把某些相關的數據放進這樣的"倉庫",並根據管理的需要進行相應的處理。
例如,企業或事業單位的人事部門常常要把本單位職工的基本情況(職工號、姓名、年齡、性別、籍貫、工資、簡歷等)存放在表中,這張表就可以看成是一個資料庫。有了這個"數據倉庫"我們就可以根據需要隨時查詢某職工的基本情況,也可以查詢工資在某個范圍內的職工人數等等。這些工作如果都能在計算機上自動進行,那我們的人事管理就可以達到極高的水平。此外,在財務管理、倉庫管理、生產管理中也需要建立眾多的這種"資料庫",使其可以利用計算機實現財務、倉庫、生產的自動化管理。
『陸』 怎樣用SQL語句查詢一個資料庫中的所有表
--讀取庫中的所有表名
select name from sysobjects where xtype='u'
--讀取指定表的所有列名
select name from syscolumns where id=(select max(id) from sysobjects where xtype='u' and name='表名')
獲取資料庫表名和欄位
sqlserver中各個系統表的作用
sysaltfiles 主資料庫 保存資料庫的文件
syscharsets 主資料庫 字元集與排序順序
sysconfigures 主資料庫 配置選項
syscurconfigs 主資料庫 當前配置選項
sysdatabases 主資料庫 伺服器中的資料庫
syslanguages 主資料庫 語言
syslogins 主資料庫 登陸帳號信息
sysoledbusers 主資料庫 鏈接伺服器登陸信息
sysprocesses 主資料庫 進程
sysremotelogins主資料庫 遠程登錄帳號
syscolumns 每個資料庫 列
sysconstrains 每個資料庫 限制
sysfilegroups 每個資料庫 文件組
sysfiles 每個資料庫 文件
sysforeignkeys 每個資料庫 外部關鍵字
sysindexs 每個資料庫 索引
sysmenbers 每個資料庫 角色成員
sysobjects 每個資料庫 所有資料庫對象
syspermissions 每個資料庫 許可權
systypes 每個資料庫 用戶定義數據類型
select 列名=name from syscolumns where id=object_id(N'要查的表名')
『柒』 我的程序,查詢資料庫很慢。請問怎麼提高查詢速度
SQL提高查詢效率
1.對查詢進行優化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
2.應盡量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
可以在num上設置默認值0,確保表中num列沒有null值,然後這樣查詢:
select id from t where num=0
3.應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。
4.應盡量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20
5.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
6.下面的查詢也將導致全表掃描:
select id from t where name like '%abc%'
若要提高效率,可以考慮全文檢索。
7.如果在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變數,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:
select id from t where num=@num
可以改為強制查詢使用索引:
select id from t with(index(索引名)) where num=@num
8.應盡量避免在 where 子句中對欄位進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where num/2=100
應改為:
select id from t where num=100*2
9.應盡量避免在where子句中對欄位進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)='abc'--name以abc開頭的id
select id from t where datediff(day,createdate,'2005-11-30')=0--『2005-11-30』生成的id
應改為:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
10.不要在 where 子句中的「=」左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
11.在使用索引欄位作為條件時,如果該索引是復合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應盡可能的讓欄位順序與索引順序相一致。
12.不要寫一些沒有意義的查詢,如需要生成一個空表結構:
select col1,col2 into #t from t where 1=0
這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:
create table #t(...)
13.很多時候用 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)
14.並不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,如一表中有欄位sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。
15.索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。
16.應盡可能的避免更新 clustered 索引數據列,因為 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引數據列,那麼需要考慮是否應將該索引建為 clustered 索引。
17.盡量使用數字型欄位,若只含數值信息的欄位盡量不要設計為字元型,這會降低查詢和連接的性能,並會增加存儲開銷。這是因為引擎在處理查詢和連接時會逐個比較字元串中每一個字元,而對於數字型而言只需要比較一次就夠了。
18.盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長欄位存儲空間小,可以節省存儲空間,其次對於查詢來說,在一個相對較小的欄位內搜索效率顯然要高些。
19.任何地方都不要使用 select * from t ,用具體的欄位列表代替「*」,不要返回用不到的任何欄位。
20.盡量使用表變數來代替臨時表。如果表變數包含大量數據,請注意索引非常有限(只有主鍵索引)。
21.避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。
22.臨時表並不是不可使用,適當地使用它們可以使某些常式更有效,例如,當需要重復引用大型表或常用表中的某個數據集時。但是,對於一次性事件,最好使用導出表。
23.在新建臨時表時,如果一次性插入數據量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然後insert。
24.如果使用到了臨時表,在存儲過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。
25.盡量避免使用游標,因為游標的效率較差,如果游標操作的數據超過1萬行,那麼就應該考慮改寫。
26.使用基於游標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。
27.與臨時表一樣,游標並不是不可使用。對小型數據集使用 FAST_FORWARD 游標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括「合計」的常式通常要比使用游標執行的速度快。如果開發時間允許,基於游標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。
28.在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句後向客戶端發送 DONE_IN_PROC 消息。
29.盡量避免大事務操作,提高系統並發能力。
30.盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理
1、避免將欄位設為「允許為空」
2、數據表設計要規范
3、深入分析數據操作所要對資料庫進行的操作
4、盡量不要使用臨時表
5、多多使用事務
6、盡量不要使用游標
7、避免死鎖
8、要注意讀寫鎖的使用
9、不要打開大的數據集
10、不要使用伺服器端游標
11、在程序編碼時使用大數據量的資料庫
12、不要給「性別」列創建索引
13、注意超時問題
14、不要使用Select *
15、在細節表中插入紀錄時,不要在主表執行Select MAX(ID)
16、盡量不要使用TEXT數據類型
17、使用參數查詢
18、不要使用Insert導入大批的數據
19、學會分析查詢
20、使用參照完整性
21、用INNER JOIN 和LEFT JOIN代替Where
提高SQL查詢效率(要點與技巧):
· 技巧一:
問題類型:ACCESS資料庫欄位中含有日文片假名或其它不明字元時查詢會提示內存溢出。
解決方法:修改查詢語句
sql="select * from tablename where column like '%"&word&"%'"
改為
sql="select * from tablename"
rs.filter = " column like '%"&word&"%'"
===========================================================
技巧二:
問題類型:如何用簡易的辦法實現類似網路的多關鍵詞查詢(多關鍵詞用空格或其它符號間隔)。
解決方法:
'//用空格分割查詢字元串
ck=split(word," ")
'//得到分割後的數量
sck=UBound(ck)
sql="select * tablename where"
在一個欄位中查詢
For i = 0 To sck
SQL = SQL & tempJoinWord & "(" & _
"column like '"&ck(i)&"%')"
tempJoinWord = " and "
Next
在二個欄位中同時查詢
For i = 0 To sck
SQL = SQL & tempJoinWord & "(" & _
"column like '"&ck(i)&"%' or " & _
"column1 like '"&ck(i)&"%')"
tempJoinWord = " and "
Next
===========================================================
技巧三:大大提高查詢效率的幾種技巧
1. 盡量不要使用 or,使用or會引起全表掃描,將大大降低查詢效率。
2. 經過實踐驗證,charindex()並不比前面加%的like更能提高查詢效率,並且charindex()會使索引失去作用(指sqlserver資料庫)
3. column like '%"&word&"%' 會使索引不起作用
column like '"&word&"%' 會使索引起作用(去掉前面的%符號)
(指sqlserver資料庫)
4. '%"&word&"%' 與'"&word&"%' 在查詢時的區別:
比如你的欄位內容為 一個容易受傷的女人
'%"&word&"%' :會通配所有字元串,不論查「受傷」還是查「一個」,都會顯示結果。
'"&word&"%' :只通配前面的字元串,例如查「受傷」是沒有結果的,只有查「一個」,才會顯示結果。
5. 欄位提取要按照「需多少、提多少」的原則,避免「select *」,盡量使用「select 欄位1,欄位2,欄位3........」。實踐證明:每少提取一個欄位,數據的提取速度就會有相應的提升。提升的速度還要看您舍棄的欄位的大小來判斷。
6. order by按聚集索引列排序效率最高。一個sqlserver數據表只能建立一個聚集索引,一般默認為ID,也可以改為其它的欄位。
7. 為你的表建立適當的索引,建立索引可以使你的查詢速度提高幾十幾百倍。(指sqlserver資料庫)
· 以下是建立索引與不建立索引的一個查詢效率分析:
Sqlserver索引與查詢效率分析。
表 News
欄位
Id:自動編號
Title:文章標題
Author:作者
Content:內容
Star:優先順序
Addtime:時間
記錄:100萬條
測試機器:P4 2.8/1G內存/IDE硬碟
=======================================================
方案1:
主鍵Id,默認為聚集索引,不建立其它非聚集索引
select * from News where Title like '%"&word&"%' or Author like '%"&word&"%' order by Id desc
從欄位Title和Author中模糊檢索,按Id排序
查詢時間:50秒
=======================================================
方案2:
主鍵Id,默認為聚集索引
在Title、Author、Star上建立非聚集索引
select * from News where Title like '"&word&"%' or Author like '"&word&"%' order by Id desc
從欄位Title和Author中模糊檢索,按Id排序
查詢時間:2 - 2.5秒
=======================================================
方案3:
主鍵Id,默認為聚集索引
在Title、Author、Star上建立非聚集索引
select * from News where Title like '"&word&"%' or Author like '"&word&"%' order by Star desc
從欄位Title和Author中模糊檢索,按Star排序
查詢時間:2 秒
=======================================================
方案4:
主鍵Id,默認為聚集索引
在Title、Author、Star上建立非聚集索引
select * from News where Title like '"&word&"%' or Author like '"&word&"%'
從欄位Title和Author中模糊檢索,不排序
查詢時間:1.8 - 2 秒
=======================================================
方案5:
主鍵Id,默認為聚集索引
在Title、Author、Star上建立非聚集索引
select * from News where Title like '"&word&"%'
或
select * from News where Author like '"&word&"%'
從欄位Title 或 Author中檢索,不排序
查詢時間:1秒
· 如何提高SQL語言的查詢效率?
問:請問我如何才能提高SQL語言的查詢效率呢?
答:這得從頭說起:
由於SQL是面向結果而不是面向過程的查詢語言,所以一般支持SQL語言的大型關系型資料庫都使用一個基於查詢成本的優化器,為即時查詢提供一個最佳的執行策略。對於優化器,輸入是一條查詢語句,輸出是一個執行策略。
一條SQL查詢語句可以有多種執行策略,優化器將估計出全部執行方法中所需時間最少的所謂成本最低的那一種方法。所有優化都是基於用記所使用的查詢語句中的where子句,優化器對where子句中的優化主要用搜索參數(Serach Argument)。
搜索參數的核心思想就是資料庫使用表中欄位的索引來查詢數據,而不必直接查詢記錄中的數據。
帶有 =、<、<=、>、>= 等操作符的條件語句可以直接使用索引,如下列是搜索參數:
emp_id = "10001" 或 salary > 3000 或 a =1 and c = 7
而下列則不是搜索參數:
salary = emp_salary 或 dep_id != 10 或 salary * 12 >= 3000 或 a=1 or c=7
應當盡可能提供一些冗餘的搜索參數,使優化器有更多的選擇餘地。請看以下3種方法:
第一種方法:
select employee.emp_name,department.dep_name from department,employee where (employee.dep_id = department.dep_id) and (department.dep_code="01") and (employee.dep_code="01");
它的搜索分析結果如下:
Estimate 2 I/O operations
Scan department using primary key
for rows where dep_code equals "01"
Estimate getting here 1 times
Scan employee sequentially
Estimate getting here 5 times
第二種方法:
select employee.emp_name,department.dep_name from department,employee where (employee.dep_id = department.dep_id) and (department.dep_code="01");
它的搜索分析結果如下:
Estimate 2 I/O operations
Scan department using primary key
for rows where dep_code equals "01"
Estimate getting here 1 times
Scan employee sequentially
Estimate getting here 5 times
第一種方法與第二種運行效率相同,但第一種方法最好,因為它為優化器提供了更多的選擇機會。
第三種方法:
select employee.emp_name,department.dep_name from department,employee where (employee.dep_id = department.dep_id) and (employee.dep_code="01");
這種方法最不好,因為它無法使用索引,也就是無法優化……
使用SQL語句時應注意以下幾點:
1、避免使用不兼容的數據類型。例如,Float和Integer,Char和Varchar,Binary和Long Binary不兼容的。數據類型的不兼容可能使優化器無法執行一些本可以進行的優化操作。例如:
select emp_name form employee where salary > 3000;
在此語句中若salary是Float類型的,則優化器很難對其進行優化,因為3000是個整數,我們應在編程時使用3000.0而不要等運行時讓DBMS進行轉化。
2、盡量不要使用表達式,因它在編繹時是無法得到的,所以SQL只能使用其平均密度來估計將要命中的記錄數。
3、避免對搜索參數使用其他的數學操作符。如:
select emp_name from employee where salary * 12 > 3000;
應改為:
select emp_name from employee where salary > 250;
4、避免使用 != 或 <> 等這樣的操作符,因為它會使系統無法使用索引,而只能直接搜索表中的數據。
· ORACAL中的應用
一個1600萬數據表--簡訊上行表TBL_SMS_MO
結構:
CREATE TABLE TBL_SMS_MO
(
SMS_ID NUMBER,
MO_ID VARCHAR2(50),
MOBILE VARCHAR2(11),
SPNUMBER VARCHAR2(20),
MESSAGE VARCHAR2(150),
TRADE_CODE VARCHAR2(20),
LINK_ID VARCHAR2(50),
GATEWAY_ID NUMBER,
GATEWAY_PORT NUMBER,
MO_TIME DATE DEFAULT SYSDATE
);
CREATE INDEX IDX_MO_DATE ON TBL_SMS_MO (MO_TIME)
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE
(
INITIAL 1M
NEXT 1M
MINEXTENTS 1
MAXEXTENTS UNLIMITED
PCTINCREASE 0
);
CREATE INDEX IDX_MO_MOBILE ON TBL_SMS_MO (MOBILE)
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE
(
INITIAL 64K
NEXT 1M
MINEXTENTS 1
MAXEXTENTS UNLIMITED
PCTINCREASE 0
);
問題:從表中查詢某時間段內某手機發送的短消息,如下SQL語句:
SELECT MOBILE,MESSAGE,TRADE_CODE,MO_TIME
FROM TBL_SMS_MO
WHERE MOBILE='130XXXXXXXX'
AND MO_TIME BETWEEN TO_DATE('2006-04-01','YYYY-MM-DD HH24:MI:SS') AND TO_DATE('2006-04-07','YYYY-MM-DD HH24:MI:SS')
ORDER BY MO_TIME DESC
返回結果大約需要10分鍾,應用於網頁查詢,簡直難以忍受。
分析:
在PL/SQL Developer,點擊「Explain Plan」按鈕(或F5鍵),對SQL進行分析,發現預設使用的索引是IDX_MO_DATE。問題可能出在這里,因為相對於總數量1600萬數據來說,都mobile的數據是很少的,如果使用IDX_MO_MOBILE比較容易鎖定數據。
如下優化:
SELECT /*+ index(TBL_SMS_MO IDX_MO_MOBILE) */ MOBILE,MESSAGE,TRADE_CODE,MO_TIME
FROM TBL_SMS_MO
WHERE MOBILE='130XXXXXXXX'
AND MO_TIME BETWEEN TO_DATE('2006-04-01','YYYY-MM-DD HH24:MI:SS') AND TO_DATE('2006-04-07','YYYY-MM-DD HH24:MI:SS')
ORDER BY MO_TIME DESC
測試:
按F8運行這個SQL,哇~... ... 2.360s,這就是差別。
http://www.cnblogs.com/ShaYeBlog/archive/2013/07/31/3227244.html
『捌』 如何在mysql中一次性查出某表中所有欄位的非空個數
NULL 對外部程序來說,具體為不知道、不確切的、無法表述的值。所以在很多家公司的開發規范里都明確規定了,必須為 NOT NULL。
其實用到 NULL 的場景都可以轉換為有意義的字元或者數值,一是有利用數據的易讀性以及後期的易維護性;二是降低 SQL 語句的編寫難度。
關於 NULL 的特性如下:
1. 參與 NULL 欄位拼接的結果都為 NULL,預期的可能會有差異
預想把欄位 r1 做個拼接,再插入到新的表 t3 里,結果 t3 表的記錄全為 NULL,跟預期不符。
mysql> show create table t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`r1` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
mysql> show create table t2\G
*************************** 1. row ***************************
Table: t2
Create Table: CREATE TABLE `t2` (
`r1` varchar(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
mysql> create table t3 like t1
Query OK, 0 rows affected (0.04 sec)
mysql> insert into t3 select concat(r1,'database') from t1 limit 2;
Query OK, 2 rows affected (0.02 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t3;
+------+
| r1 |
+------+
| NULL |
| NULL |
+------+
2 rows in set (0.00 sec)
那正確的方法如下,對 NULL 用函數 IFNULL 特殊處理。
mysql> insert into t3 select concat(ifnull(r1,''),'database') from t1 limit 2;
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t3;
+----------+
| r1 |
+----------+
| database |
| database |
+----------+
2 rows in set (0.00 sec)
2. 對於包含 NULL 列的求 COUNT 值也不準確
t1 和 t2 的記錄數是一樣的,但是欄位 r1 包含了 NULL,這導致結果忽略了這些值。
mysql> select count(r1) as rc from t1;
+-------+
| rc |
+-------+
| 16384 |
+-------+
1 row in set (0.01 sec)
mysql> select count(r1) as rc from t2;
+-------+
| rc |
+-------+
| 32768 |
+-------+
1 row in set (0.03 sec)
這時候我們可能想到了,正確的方法是用 NULL 相關函數處理,
mysql> select count(ifnull(r1,'')) as rc from t1;
+-------+
| rc |
+-------+
| 32768 |
+-------+
1 row in set (0.03 sec)
或者是直接用 COUNT(*) 包含了所有可能的值
mysql> select count(*) as rc from t1;
+-------+
| rc |
+-------+
| 32768 |
+-------+
1 row in set (0.02 sec)
當然了不僅僅是 COUNT,除了 NULL 相關的函數,大部分對 NULL 處理都不友好。
所以其實從上面兩點來看,NULL 的處理都得特殊處理,額外增加了編寫 SQL 的難度。
3. 包含 NULL 的索引列
對包含 NULL 列建立索引,比不包含的 NULL 的欄位,要多佔用一個 BIT 位來存儲。
示例
key_len 分別為 43 和 42,t1 比 t2 多了一個位元組,那這里可能有人要問了,不是說佔了一個 BIT 位嗎?那為什麼多了一個位元組?可以關注我上一篇文章(第02期:MySQL 數據類型的藝術 - 大對象欄位)關於 BIT 的詳細描述。
mysql> pager grep -i 'key_len'
PAGER set to 'grep -i 'key_len''
mysql> explain select * from t1 where r1 = ''\G
key_len: 43
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from t2 where r1 = ''\G
key_len: 42
1 row in set, 1 warning (0.00 sec)
4. 各存儲引擎相關的對 NULL 的處理
在 MySQL 8.0 發布後,僅有 InnoDB、MyISAM 和 Memory 支持對包含 NULL 列的索引,其他引擎不支持。比如 NDB。
『玖』 存儲過程裡面怎麼調用explain
使用JDBC驅動程序調用不帶參數的存儲過程時,必須使用callSQL轉義序列,ResultSet rs = stmt.executeQuery("{call dbo.ProcereName}"); 調用帶參數的存儲過程時,必須結合 SQLServerConnection 類的 prepareCall 方法使用 call SQL 轉義序列 CallableStatement cstmt = con.prepareCall("{call dbo.ProcereName(?, ?)}"); cstmt.setInt(1, java.sql.Types.INTEGER); cstmt.registerOutParameter(2, java.sql.Types.VARCHAR); cstmt.execute(); System.out.println("MANAGER ID: " + cstmt.getInt(1));System.out.println("MANAGER NAME: " + cstmt.getInt(2));