1. 程式人生 > >Mysql中select的正確姿勢

Mysql中select的正確姿勢

  大家在開發中,還有很多童鞋在寫查詢語句的時候,習慣寫下面這種不規範sql
  
  select * from table
  
  而不寫成下面的這種規範方式
  
  select col1,col2,...,coln from table
  
  我也知道,這些童鞋是圖方便,畢竟再敲一堆的列名,嫌麻煩!
  
  你們上班可以問問自己的同事
  
  你:“xx,知道select *和select所有欄位的區別麼?
  
  同事:"額。。額。。額。。"
  
  留下的只有尷尬的笑容!
  
  我也知道,很多人至今都沒有搞懂select *和selct 所有欄位的區別
  
  因此,我開一文來說明一下。另外,我選的是自己最熟悉的mysql資料庫,此文的結論在oralce,sqlserver上是否成立,博主沒做過測試。
  
  正文
  
  (select所有欄位)效能高?
  
  網路上流傳著一種說法說是
  
  “*” 表示通配所有欄位,在SQL的機制裡,需要先識別統計所有欄位再進行下一步。
  
  明確指定欄位的話,會減少上述的操作,所以效率有所提升。
  
  然而,實際上呢?效率是相差不大的!。
  
  取部落格
  
  http://flysnowxf.iteye.com/blog/1125032
  
  的測試結果
  
  mysql 5.1.37
  
  表記錄數41,547,002,即4000w行
  
  使用遠端客戶端取1000條資料,統計時間:
  
  SELECT * FROM `dmsp`.`dmsp_dimension_content` LIMIT 0, 1000;
  
  時間2.218s,網路消耗0.547s
  
  SELECT `id`, `appid`, `aop`, `t`, `uid`, `sid`, `pid`, `pname`, `bid`, `bname`, `ptype`, `sm`, `sv`, `bt`, `national`, `area`, `ov` FROM `dmsp`.`dmsp_dimension_content` LIMIT 0, 1000;
  
  取出所有欄位,時間2.250s,網路消耗0.578s
  
  可以看出,這二者的時間差幾乎可以忽略,另外還有一本書上的內容也可以佐證我的話。
  
  《SQL CookBook》第一章 檢索記錄中1.1小節(原書第十五頁內容如下):
  
  image
  
  此書也說明了,兩種方式在效能上幾乎是沒有差距的。
  
  那為什麼還是不推薦select * ?
  
  網路IO問題
  
  很多文章裡說什麼,會帶來額外的記憶體、磁碟、cpu的開銷。對此,我有自己的觀點。我覺得這不是主要原因。主要原因是帶來了額外的網路開銷。
  
  在一個系統中,記憶體、磁碟、cpu的開銷,不過是微妙級。造成系統的延遲的重頭戲是網路開銷。網路開銷可能帶來秒級的延遲。當然,如果你的應用程式和資料庫是在同一臺機器上的,那當我沒說這句話!
  
  select *會查詢出不需要的、額外的資料,那麼這些額外的資料在網路上進行傳輸,必定會造成效能延遲。假設你的table中,有一個列的型別為binary。此時,你的select *操作,就會十分緩慢,並且會造成額外的網路開銷。
  
  索引問題
  
  仔細看下面的兩句sql
  
  select col1 from table;
  
  select * from table;
  
  如果col1欄位包含索引資訊,那麼此時,這兩句的sql執行時間可能會有幾十上百倍的差異。
  
  在col1欄位有索引的情況下,mysql是可以不用讀data,直接使用index裡面的值就返回結果的。但是一旦用了select *,就會有其他列需要讀取,這時在讀完index以後還需要去讀data才會返回結果。這樣就造成了額外的效能開銷。
  
  ps:我不想在這裡扯什麼覆蓋索引,輔助索引的概念。其實要講的很專業,扯一堆高大上的名詞,我也可以。只是這樣徒增讀者的理解難度,儘量用通俗的方式來講。
  
  擴充套件性問題
  
  有的人會覺得
  
  使用select * ,這樣在增加列的時候,不用改sql,方便!
  
  然而實際上,你的sql是不用改了,但是對你的程式程式碼是有很大的影響的!
  
  身為一名21世紀的優良程式設計師,我們是不能獲取自己需要的東西的!你因為一時高興,執行了select *,如果增加或刪除列,會對你的程式碼有著極大的影響。
  
  反過來,如果你select 指定列,只獲取自己需要的幾列,表結構的修改,對你程式碼的影響就會小很多。相比之下,風險就沒有那麼大了!
  
  另外就是,對於其他人接手你專案的人來說,看到select 指定列的方式,可讀性更強,對於他們來說更好上手!
  
  E:\app\Administrator www.ysyl157.com admin\orcl\dpdump
  
  2、建立使用者
  
  create user testdb65 identified by “testdb65”
  
  default tablespace users temporary tablespace temp;
  
  使用者授權
  
  grant connect,dba to testdb65;
  
  3、建立表空間
  
  CREATE TABLESPACE HR_DATA01 DATAFILE ‘D:\nhsj\hr_data01.dbf’ SIZE 500M AUTOEXTEND ON NEXT 50M EXTENT MANAGEMENT LOCAL UNIFORM SIZE 256K ; 【建立表空間】
  
  4、匯入 bgyhr2是來源庫
  
  impdp testdb65/

[email protected] schema=www.mcyllpt.com testdb65 dumpfile=TESTDB65.dmp
  
  匯出 scott 是要匯出的庫
  
  expdp lfwtrain/[email protected] schema=當前使用者 dumpfile=expdptest.dmp
  
  (18)重導dmp檔案
  
  Oracle儲存資料時一般以DMP檔案的形式進行儲存
  
  本部落格記錄,DMP檔案的匯入 先開啟CMD
  
  sqlplus /nolog
  
  以sysdba連線
  
  conn /as sysdba
  
  這裡建立表空間,因為表空間進行儲存的話,可以提供系統性能
  
  CREATE TABLESPACE DATA01 DATAFILE 'D:\tablespace\data01.dbf' SIZE 100M AUTOEXTEND ON NEXT 50M EXTENT MANAGEMENT LOCAL UNIFORM SIZE 256K ;
  
  建立使用者
  
  CREATE USER job IDENTIFIED BY job DEFAULT TABLESPACE DATA01 TEMPORARY TABLESPACE TEMP QUOTA UNLIMITED ON DATA01
  
  授權
  
  grant connect,dba to job;
  
  複製dmp檔案到oracle安裝目錄裡的app\admin\orce\dpdump裡,然後用以下程式碼匯入dmp檔案,要順便匯入logfile的話,加上logfile=檔名
  
  impdp job/
[email protected]
schemas=www.dasheng178.com/ job dumpfile=EXPDP160810GZ.dmp
  
  (19)vm_concat函式
  
  函式wm_concat(列名),該函式可以把列值以","號分隔起來,並顯示成一行
  
  ps:這個列轉行函式vm_comcat(www.yinmaoyule178.com)在oracle10比較穩定,到了oracle11就會出現一些不相容的情況,oracle12版本就沒這個函數了
  
  (20)replace函式
  
  REPLACE(char, search_string [, replacement_string ] )
  
  char : 等待替換的字串
  
  search_string : 搜尋需要替換的字串
  
  replacement_string : 替換字串
  
  如果replacement_string預設或者為null,那麼所有char中出現的search_string 都將被移除
  
  如果search_string為null,那麼結果就是char
  
  例子:過濾某個欄位的換行符
  
  select replace(a, chr(10)) from tableA
  
  1
  
  (21) instr函式
  
  格式一:instr(www.ylouyi3.com string1, string2 ) / instr(源字串, 目標字串)
  
  格式二:instr( string1, string2 [, start_position [, nth_appearance ] ] ) / instr(源字串, 目標字串, 起始位置, 匹配序號)
  
  解析:string2 的值要在string1中查詢,是從start_position給出的數值(即:位置)開始在string1檢索,檢索第nth_appearance(幾)次出現string2。
  
  例子:查詢某個資料欄位是否包含換行符
  
  select * from tableA where instr(a,chr(10))>0