今天就跟大家聊聊有關(guān)Java開發(fā)者編寫SQL語句時常見錯誤分別有哪些,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
成都創(chuàng)新互聯(lián)主營梅縣網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶App定制開發(fā),梅縣h5小程序設(shè)計搭建,梅縣網(wǎng)站營銷推廣歡迎梅縣等地區(qū)企業(yè)咨詢
Java開發(fā)者對于面向?qū)ο缶幊趟季S與命令行編程思維的協(xié)調(diào)程度,取決于他們?nèi)缦聨追N能力的水平:
技巧(任何人都可以編寫命令行形式的代碼)教條(有的人使用“模式 - 模式”的方式,即模式無處不在,并以名字作為標(biāo)識)情緒狀況(在初期,真正面向?qū)ο笮问降拇a比起命令式代碼會更加難懂。)
但是,當(dāng)Java開發(fā)人員編寫SQL語句時,一切都變得不同了。SQL是一種說明式語言,與面向?qū)ο笏枷牒兔钍剿枷霟o關(guān)。在SQL語言中,查詢非常容易表達。但它也不是那么容易以最佳或最正確地方式編寫出來。開發(fā)人員不僅需要重新思考自己的編程模式,還需要從集合論的角度進行深入思考。
以下是Java開發(fā)人員使JDBC或jOOQ編寫SQL語句時,幾種常見的錯誤:
1.忘記了NULL
誤解NULL的含義可能是Java開發(fā)人員編寫SQL最常犯的錯誤。這有可能是因為NULL也被稱為UNKNOWN,但也有其他的原因。當(dāng)然如果它只被叫做UNKNOWN,會更容易理解一些。另一個原因是,JDBC在獲取數(shù)據(jù),或綁定變量時,SQL中的NULL被映射到Java中的null。這可能會導(dǎo)致人們認(rèn)為類似Java中null==null的情況,SQL中也存在NULL= NULL。
一個更離奇的誤解NULL的例子是,當(dāng)NULL謂詞用于行值表達式時。
另一個微妙的問題產(chǎn)生與對NOTIn 反連接中NULL含義的誤解。
解決辦法
不斷的訓(xùn)練自己。要時刻明確NULL的含義,每次你寫SQL時,都要考慮:
對于NULL來說謂詞是否正確?NULL是否影響該函數(shù)的結(jié)果?2.在Java內(nèi)存中處理數(shù)據(jù)
一些Java開發(fā)者十分了解SQL特性。偶爾JOIN,零散的UNION,沒什么問題。但如果遇到視窗功能,結(jié)果集分組等情況又怎么樣呢?很多Java開發(fā)人員會把SQL數(shù)據(jù)加載到內(nèi)存,把數(shù)據(jù)轉(zhuǎn)換成一些適合的集合類型,以十分冗長的循環(huán)結(jié)構(gòu)在集合上執(zhí)行惱人數(shù)學(xué)運算(至少在Java 8改進容器之前是這樣的)。
但一些SQL數(shù)據(jù)庫除了支持SQL標(biāo)準(zhǔn)外,還支持先進的OLAP特性,執(zhí)行效率更好,且更容易編寫。一個非標(biāo)準(zhǔn)的例子就是甲骨文的MODEL子句。只是讓數(shù)據(jù)庫進行數(shù)據(jù)處理過程,將最終獲取的結(jié)果加載到Java內(nèi)存中。因為一些非常聰明的人已經(jīng)優(yōu)化了這些昂貴的產(chǎn)品。所以,事實上,通過向OLAP數(shù)據(jù)庫上進行遷移,您將得到兩個好處:
簡潔。它可能使得在SQL中編寫正確代碼會比在Java中相對容易性能。該數(shù)據(jù)庫將可能比你的算法要快。更重要的是,你不必再通過網(wǎng)絡(luò)傳輸數(shù)百萬條記錄。解決辦法
每次你在Java中實現(xiàn)以數(shù)據(jù)為中心的算法時,要試著問問自己:有沒有辦法讓數(shù)據(jù)庫執(zhí)行這些工作,而只把結(jié)果交付給我?
3.盡量使用UNION,而不是UNION ALL
相對于UNION,UNION ALL需要額外的關(guān)鍵字顯得相形見絀。如果在SQL標(biāo)準(zhǔn)已定義如下支持,那將會好很多:
UNION(允許重復(fù))UNION DISTINCT(去掉重復(fù))一般很少需要去除重復(fù)(有時去重甚至是錯誤的),而且對于具有很多列的大結(jié)果集,它往往很慢,因為這兩個子查詢需要排序,每個元組都需要與隨后的元組進行比較。
需要注意的是,即使SQL標(biāo)準(zhǔn)指定了INTERSECTALL和EXCEPTALL,但幾乎沒有任何數(shù)據(jù)庫實現(xiàn)這些用處不大的操作。
解決辦法
你每次寫到UNION時,要考慮下你是否實際上想寫的是UNIONALL。
4.使用JDBC分頁功能將大量結(jié)果分頁
大多數(shù)數(shù)據(jù)庫都支持通過LIMIT.. OFFSET,TOP .. START AT、OFFSET.. FETCH等子句以某種方式對結(jié)果進行分頁。在沒有對這些子句的支持下,但仍然有ROWNUM(Oracle)或ROW_NUMBER()OVER()(DB2,SQL Server 2008和更低版本),這比在內(nèi)存中分頁要快得多。而且這對于大數(shù)據(jù)集更是明顯。
解決辦法
只要使用那些子句或工具(如jOOQ),可以為你模擬上述分頁子句。
5.將Java內(nèi)存中實現(xiàn)連接
從SQL的發(fā)展的初期,一些開發(fā)商在面對SQL連接時仍然有一種不安的感覺。一直存在著一種固有的恐懼---JOIN速度緩慢。如果基于成本的優(yōu)化器選擇執(zhí)行嵌套循環(huán),創(chuàng)建一個連接表源之前,加載完整表到數(shù)據(jù)庫內(nèi)存,那速度確實十分緩慢。但很這少發(fā)生。通過適當(dāng)?shù)闹^詞,約束和索引,MERGEJOIN和 HASHJOIN操作是非常快的。這與正確的元數(shù)據(jù)相關(guān)(我不用再舉Tom Kyte的例子了)。然而,也有仍然可能有不少Java開發(fā)人要會從單獨的查詢中加載兩個表到map容器中,在java內(nèi)存中以某種方式進行連接操作。
解決辦法
如果你從多個步驟的多個表中進行了SELECT操作,那要慎重考慮一下是否可以在一條語句中表達你所需要的查詢功能。6.使用DISTINCT或UNION從一個笛卡爾積中刪除重復(fù)
冗長連接的存在,會導(dǎo)致SQL語句中起作用的關(guān)系顯得十分松散。具體地,如果涉及到多列外鍵關(guān)系,很有可能忘記在JOINON子句上添加謂詞。這可能會導(dǎo)致重復(fù)的記錄,但也許只在特殊情況下。然后一些開發(fā)者可能會選擇使用DISTINCT再次刪除這些重復(fù)記錄。這種錯誤有三種危害:
可能治標(biāo)不治本。甚至在某些邊緣情況下,標(biāo)都治不了這在有很多列的大結(jié)果集上會十分的緩慢。DISTINCT會執(zhí)行ORDER BY操作來刪除重復(fù)。這在大型笛卡爾積中也十分的緩慢,因為這樣做仍然會導(dǎo)致在內(nèi)存中加載大量數(shù)據(jù)。解決辦法
作為一個經(jīng)驗法則,當(dāng)你得到不想要的重復(fù)結(jié)果時,應(yīng)該首先檢查你的連接謂詞。因為有可能是在某個地方存在著一個不易察覺的笛卡爾積。
7.不使用MERGE語句
嚴(yán)格意義上講,這不是一個真正的錯誤,可能只是對于功能強大的MERGE語句缺乏足夠的認(rèn)知或存在著某種恐懼而已。有些數(shù)據(jù)庫包括其他形式的UPSERT 語句,如MySQL的ONDUPLICATE KEY UPDATE子句。但MERGE真的十分強大,最重要的是在數(shù)據(jù)庫中,它在很大程度上擴展了SQL標(biāo)準(zhǔn),如SQL Server。
解決辦法
如果你通過鏈接INSERT和UPDATE或鏈接SELECT... FOR UPDATE來實現(xiàn)UPSERTING,那么你要多想一想。拋開與運行條件的風(fēng)險,你也許可以使用一個簡單的MERGE語句來達到目的。
8.使用了聚合函數(shù),而不是窗體功能
引入窗函數(shù)之前,使用GROUPBY子句與投影聚合函數(shù)是匯總數(shù)據(jù)的唯一方式。這在大部分情況下都十分有效,如果聚集后的數(shù)據(jù)需要由常規(guī)的數(shù)據(jù)進行補充,該分組的查詢可以置于連接子查詢中。
但是,SQL:2003定義了窗口功能,目前很多主流的數(shù)據(jù)庫廠商也紛紛實現(xiàn)了窗口功能。窗口功能可以聚集結(jié)果集中未被分組的數(shù)據(jù)。事實上,每個窗口的功能支持自身獨立的PARTITIONBY子句,這對于報表類應(yīng)用是一個非常有用的工具。
使用窗口功能將:
導(dǎo)致更多的可讀性SQL(減少子查詢中非專用GROUP BY子句的存在)提高性能,作為一個RDBMS很可能更容易優(yōu)化其窗口功能。解決辦法
當(dāng)你在一個子查詢寫一個GROUPBY子句時,仔細(xì)想想這是否能用一個窗口函數(shù)來完成。
9.使用內(nèi)存排序法進行間接排序
在SQLORDER BY子句支持多種類型的表達式,包括CASE語句,這對間接排序非常有用。你應(yīng)該永遠(yuǎn)可能在Java內(nèi)存中對數(shù)據(jù)進行排序,因為你認(rèn)為:
SQL排序太慢SQL排序不能做到這一點解決辦法
如果你在內(nèi)存中對任何SQL數(shù)據(jù)進行排序,請仔細(xì)想想,你是否能把排序遷移至數(shù)據(jù)庫中。這和將分頁遷移至數(shù)據(jù)庫中的原因一樣。
10 一個接一個的插入大量的記錄
JDBC包含了批處理,而且你應(yīng)該使用它。面對成千上萬的記錄,切勿為每一條記錄都創(chuàng)建一個新的PreparedStatement來進行插入操作。如果你要將所有記錄都插入到同一個表,使用單一的SQL語句和多個綁定值集合建立一個批處理的INSERT語句。根據(jù)您的數(shù)據(jù)庫和數(shù)據(jù)庫配置,您可能需要在一定數(shù)量的插入的記錄后進行提交,為了保持UNDO日志不過分龐大。
解決辦法
始終批量插入大型數(shù)據(jù)集。
Java開發(fā)者編寫SQL語句時常見的10種錯誤,大家是不是有了大概了解,希望在編寫的過程中一定要特別注意!
看完上述內(nèi)容,你們對Java開發(fā)者編寫SQL語句時常見錯誤分別有哪些有進一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。