用Select×進行SQL查詢的七宗罪

2020-12-13 騰訊網

  【51CTO.com快譯】如今,網上許多文章都已明確地指出:使用「SELECT * 」作為SQL查詢方式是一種極其危險的代碼書寫習慣。開發人員應該儘量在自己的程序中避免出現此類查詢,取而代之的應該是明確地指定要查詢的列名。不過,大家可能只是「知其然,而不知其所以然」。在本文中,讓我向各位初級開發人員詳細解釋,此類SQL查詢最佳實踐背後的具體原因。

  首先,我們經常面對的客觀情況是:在Oracle資料庫中,許多SQL開發人員都是從接觸「SELECT * from EMP」(EMP為表的名稱)之類的查詢語句,開始學習SQL語言的。因此,除非能夠給出充分的理由,否則我們很難撼動他們使用此類便捷查詢語句的習慣。

  下面,我將根據自己在應用編程中的實際經驗,向大家證明使用Select * from table進行SQL查詢的「七宗罪」。

  1. 不必要的I/O(輸入/輸出)

  通過使用SELECT * ,您雖然可以獲得一些完全可以被忽略的返回數據,但是該獲取過程可並不是免費的。那些本來可能只需要從索引頁面中讀取的數據檢索,如今您卻不得不從各個頁面中以全量的方式讀取出來。顯然,此舉會導致資料庫端白白浪費各種有限的I/O周期。

  另外,該方式也可能會拖慢您的查詢速度。如果您好奇並想探究資料庫後臺的查詢執行過程,以及查詢引擎是如何順次處理查詢語句的話,我建議您參考:Markus Winand的《SQL Performance Explained》(請參見http://www.amazon.com/Performance-Explained-Everything-Developers-about/dp/3950307826/?tag=javamysqlanta-20),以及Udemy的《The Complete SQL BootCamp》(請參見https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&subid=0&offerid=323058.1&type=10&tmpid=14538&RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fthe-complete-sql-bootcamp%2F)課程。

  2. 增加的網絡流量

  SELECT * 雖然能返回比用戶預期更多的數據,但是相應地,這些數據的傳輸勢必會消耗更多的網絡帶寬資源。與此同時,網絡帶寬的增加也就意味著:那些真正為用戶所需要的數據將會花費更長的時間,才能被傳送到客戶端的應用程式上。例如:如果您可能是在本地計算機上運行由SQL Server Management Studio(請詳見http://bit.ly/2CXPyBB)、Toad或SQL Developer for Oracle(請參見http://bit.ly/2xQzAsd)提供的查詢編輯器,或是在某個Java應用伺服器上運行此類查詢,這都會耗費您不少的網絡流量與資源。

  3.更多的應用內存

  隨著業務數據的猛增,您的應用程式可能需要使用更多的內存,來保存由此類查詢方式所產生的,可能來自Microsoft SQL Server(請參見http://www.java67.com/2018/01/top-4-free-microsoft-sql-server-books.html)的各種無用數據。

  4.產生依賴於列排序的結果集(ResultSet)

  當您在應用程式中使用SELECT * 查詢後,您會得到一些依賴於數據表的列排序的結果集。因此,一旦有新的列被添加,或者是列排序被修改了,它們都會對查詢的結果集產生不同的影響。

  5.新增列會破壞既有的視圖

  如果您在視圖(請參見http://www.java67.com/2012/11/what-is-difference-between-view-vs-materialized-view-database-sql.html)中使用了SELECT * ,那麼一旦有新的列被添加,同時舊的列從表中被去除時,您所構建的原有視圖就會被破壞,進而返回給用戶錯誤的結果。

  為避免此類情況的發生,您應該始終在SQL Server資料庫(請參見http://javarevisited.blogspot.sg/2013/11/difference-between-char-varchar-nchar-nvarchar-sql-database.html#axzz5CSnhvSWV)裡,對於視圖的定義中,包含WITH SCHEMABINDING選項。

  6. 連接查詢中的衝突

  如果您在連接查詢(JOIN Query,請參見https://javarevisited.blogspot.com/2012/11/how-to-join-three-tables-in-sql-query-mysql-sqlserver.html#axzz5az3hfsHW)中使用了SELECT * ,那麼一旦在多個表中出現了具有相同名稱的列,例如status、active和name等,就可能會產生各種並髮式的衝突。

  雖說在直接查詢中,出現問題的可能性不大,但是當您試著按其中的某一列進行排序、或是在公用表表達式(Common Table Expression,CTE)、以及派生表(derived table)中使用查詢的時候,您就需要進行各種進一步的調整,以避免產生衝突了。

  7.在表間複製數據時的風險

  您可能會經常使用「SELECT * into INSERT . . .」之類的語句,以實現將某些數據從一張表複製到另一張表。如果在兩張表中,各個列的排列順序略有不同,那麼就可能會出現將不正確的數據複製到錯誤列中的情況。

  一些程式設計師可能會認為:由於查詢解析器必須額外地驗證某些靜態值,因此導致了在EXISTS語句(譯者註:即檢驗查詢的結果是否返回數據,請參見https://javarevisited.blogspot.com/2016/01/sql-exists-example-customers-who-never-ordered.html)中使用SELECT * 要比SELECT 1的速度更快一些。此觀點擱在過去可能會有幾分道理。但是現在,各種資料庫解析器已經發展得相當智能了,它們判斷EXISTS語句的效率,與產生SELECT結果列表(請參見https://javarevisited.blogspot.com/2016/04/how-to-convert-result-of-select-command-to-comma-separated-String-in-SQL-Server.html)將毫無關係。

  結論

  通過上述七點分析,相信您應該明白了為什麼不能在SQL查詢中濫用SELECT * 的原因吧?可見,您應該儘可能地在查詢中,使用顯式的列名稱,而不是那些星號通配符。此舉不但能夠提高您的代碼效率,也可以使您的程序更加清晰。與此同時,該方法還能夠幫助您創建各種具有可維護性的代碼。而且,如果後期在表中有新的一列被添加的話,您的代碼也不會因此受到影響,您仍然會擁有來自原始數據表的參考視圖。

  原文標題:7 Reasons Why Using SELECT * FROM TABLE in SQL Query Is a Bad Idea,作者:Javin Paul

  【51CTO譯稿,合作站點轉載請註明原文譯者和出處為51CTO.com】

相關焦點

  • MySQL資料庫SQL查詢優化技巧之SELECT
    查詢語法和使用方法,以及SELECT的執行流程,了解了SELECT的執行流程還是很重要的,重要我們才能有針對性地去進行優化,比如select在執行的時候 會把所以的欄位編程成大寫字母,這樣我們在起初編寫SELECT語句時就可以把所以的字母進行大寫,這樣就省去了程序為把SQL語句變成大寫的消耗,速度自然就會提高。
  • sql子查詢面試題
    這是《從零學會sql》系列課程第4節課《複雜查詢》的練習題,也是常考常考的面試題。
  • 分組查詢時,select的欄位是否一定要都在group by中?
    分組查詢關鍵字group by通常和集合函數(MAX、MIN、COUNT、SUM、AVG)一起使用,它可以對一列或者多列結果集進行分組。
  • SQL系列:當INSERT遇到SELECT...
    作為開發,在實際工作中經常會和資料庫打交道,會用高效快捷的sql語句如有神助般,提高工作效率。
  • SQL基礎培訓--SQL語言基本概念及簡單查詢
    什麼是SQL語句,及簡單的寫法sql 語句是對資料庫進行操作的一種語言。結構化查詢語言(Structured Query Language)簡稱SQL,結構化查詢語言是一種資料庫查詢和程序設計語言,用於存取數據以及查詢、更新和管理關係資料庫系統。
  • Oracle常用經典SQL查詢(一)
    註:本文的查詢測試以oracle11.2.0.4.0企業版作為查詢測試,截圖只是為了證明SQL的可用性及正確性,查詢結果因測試環境不同各有差異
  • oracle sql 查詢突然變慢-百家號 - 百度經驗
    一條sql突然執行變慢,耗時9秒,應用是不能改的,只能從資料庫方面下手解決步驟思路:1:查看sql是否走索引2:查看索引是否失效3:hint 強制走索引(只是用來查看hint狀態下,查詢是否更改,應用是不能改的)4:收集該表所有信息(包括索引)5:分析該表所有信息(包括索引)6:再次執行並查看注意
  • 追加查詢 select into from和insert into select的區別
  • 產品經理學SQL(二)一天學會用SQL解決業務查詢問題
    本篇文章意在幫助大家系統地入門SQL,教大家如何解決sql查詢任務。前言回顧一下,上一篇文章我們已經知道了SQL語言的基本框架,並能完成簡單的單表查詢和雙表連接查詢。這篇文章希望能幫助你系統地入門SQL,從而解決產品經理80%的sql查詢任務。和上篇的一個小時入門SQL一樣,這篇文章的建議學習時間為一天。
  • SQL語句面試題目:一般查詢和高級子查詢(上)
    [plain] view plain copyselect last_name, hire_date  from employees  where hire_date = last_day(hire_date) – 1   2. 查詢出 last_name 為 'Chen' 的 manager 的信息.
  • 基礎SQL-DQL語句-SELECT查詢的簡單使用以及IFNULL函數
    基礎SQL-DQL語句-SELECT查詢的簡單使用以及IFNULL函數分類描述關鍵字DQL(Data Query Language)數據查詢語言 (掌握)DQL語言並不是屬於MYSQL官方的分類,但是對資料庫的操作最多就是查詢,所以我們的程式設計師把查詢語句的語句稱作為DQL語言SELECT 等查詢不會對資料庫中的數據進行修改.只是一種顯示數據的方式
  • MySQL數據查詢select語句靈活使用詳解
    案例:查詢用戶表user的所有信息Select * from user第二種:帶有條件篩選的單表查詢 where這個語法只是在select查詢語句的最好加上一條where語句進行數據的進一步過濾。第四種:過濾相同列數據 distinct如果我們得到的查詢結果中有相同的數據行,我們可以通過distinct關鍵詞進行過濾。語法結構:select distinct 欄位 from 表沒錯,只需要在查詢select關鍵詞後加上distinct關鍵詞即可。舉例:查詢用戶表一共有哪些用戶暱稱。
  • SQL 查詢優化之 WHERE 和 LIMIT 使用索引的奧秘
    查詢結果:第一條要5.018s,第二條0.016s為什麼會是這樣的結果呢?第一,acct_id和create_time都有索引,不應該出現5s查詢時間這麼慢啊 仔細觀察會發現,索引只使用了idx_create_time,沒有用到idx_acct_id。這能解釋第一條sql很慢,因為where查詢未用到索引,那麼第二條為什麼這麼快?看起來匪夷所思,其實搞清楚mysql查詢的原理之後,其實很簡單。
  • 如何用 SQL 的方式打開 Pandas?
    # 導入相關庫import numpy as npimport pandas as pdfrom pandasql import sqldf, load_meat, load_births基礎pandasql 中的主要函數是 sqldf,它接收兩個參數:一個SQL 查詢語句;一組會話/環境變量(locals() 或 globals
  • 學習MySQL的select語句
    select語句可 以用回車分隔$sql="select * from article where id=1"和  $sql="select * from article where id=1">都可以得到正確的結果,但有時分開寫或許能 更明了一點,特別是當sql語句比較長時。
  • 優化SQL查詢:如何寫出高性能SQL語句
    執行計劃是資料庫根據SQL語句和相關表的統計信息作出的一個查詢方案,這個方案是由查詢優化器自動分析產生的,比如一條SQL語句如果用來從一個 10萬條記錄的表中查1條記錄,那查詢優化器會選擇「索引查找」方式,如果該表進行了歸檔,當前只剩下5000條記錄了,那查詢優化器就會改變方案,採用 「全表掃描」方式。
  • desc巧用及反引號 ` SQL注入——【61dctf】 inject writeup
    $_GET['table']:"test";$table = Filter($table);mysqli_query($mysqli,"desc `secret_{$table}`") or Hacker();$sql = "select 'flag{xxx}' from secret_{$table}";$ret = sql_query($sql);echo $ret[0];?
  • 資料庫SQL腳本優化
    3、儘量用表連接代替子查詢,因為子查詢會在查詢前建立臨時表,查詢完又刪除臨時表,對於結果集大的查詢,性能影響更加明顯4、避免沒有where過濾條件的查詢 (前兩天就看到一個查詢bc_freight(400W+)表裡所有數據,沒有過濾條件,我看到的時候已經執行一萬多秒了)5、sql語句儘可能簡單點
  • 打造出色查詢:如何優化SQL查詢?
    1.嘗試不去用select *來查詢SQL,而是選擇專用欄位。反例:select * from employee;正例:select id,name fromemployee;理由:· 通過只用必要欄位進行查詢
  • Mysql中一條SQL查詢語句是如何執行的?
    2.查詢流程解析select * from table1 where ID=10;這條語句相信大家再熟悉不過了,下面我們就看看這一條語句在mysql中是怎麼執行的。第一步:一條sql語句要經過連接器,客戶端要和mysql建立連接。