昨天公司的技術微信公衆號貼了一篇關於怎麼檢索一天全部訂單的SQL的寫法問題。相似: SELECT order_no FROM orders WHERE create_time >= '2015-04-07 00:00:00' AND create_time <= '2015-04-07 23:59:59',文中提到這種寫法是有問題的,可能有部分訂單落在最後一秒(create_time是Timestamp類型),這樣在進行對帳等環節可能帶來很隱藏的bug,很難被發現。文中還給出了MySQL中的方案推薦這樣寫 SELECT order_no FROM orders WHERE create_time >= '2015-04-07 00:00:00' AND create_time < '2015-04-08 00:00:00'。數據庫
就這麼個問題在吃飯的時候和幾個同事進行了熱(面)情(紅)洋(耳)溢(赤)的討論。有同事說他會在傳給SQL的參數的截至時間拼接上.999。也即把毫秒數給拼接到截至時間裏,這樣就能『正確地』查詢當天全部訂單了。看起來是正確的,由於就目前主流的MySQL版本(5.5, 5.6。5.5版本Timestamp精度支持到秒,5.6版本支持到毫秒)是能把一天的全部時間都包括。當時咱們表示拼接上.999難以理解,這就至關於咱們常說的magic number同樣,會給維護代碼帶來障礙。你們以爲使用create_time >= '2015-04-07 00:00:00' AND create_time < '2015-04-08 00:00:00'更無歧義一些。不過這位同事給了另一個理由:由於他在使用SQL定義時間範圍的時候更習慣使用btween ... and ... 。好吧,若是這也算是一個理由的話。性能優化
不過這讓我忽然感到有點羞愧:我竟然不知道between ... and ...表示的是開開,開閉,閉開仍是閉閉區間。在詢問了幾個同事,都吞吞吐吐表示是閉閉區間,甚至有位同事還去查了下MySQL官網以後,我以爲SQL的btween ... and ...設計得真扯淡。使用between ... and ...比添加.999更惡劣,由於這讓我這個不知道這個區間的人感到羞愧,最起碼我還知道.999是毫秒。人在被人弄得羞愧後第一個反應就是義正詞嚴的進行反駁,以隱藏這種羞愧感。在思考了幾秒鐘後我反駁道使用between ... and ...很差,不推薦使用。若是你想來描述一個區間範圍的話用大於等於,小於等於這樣的方式會讓代碼更讓人容易理解(好比,create_time >= '2015-04-07 00:00:00.000' AND create_time <= '2015-04-08 00:00:00.999',雖然我不想認可加.999是對的),代碼更易讀,由於就算不知道between ... and ...實際區間含義的人都知道這是什麼意思(說完這句話,個人羞愧感大大下降了,甚至有點驕傲的感受)。微信
可是,在我驕傲的時候,這位同事給我當頭一棒:你不記得between ... and ...是你的事,可是我記得啊,我第一次看到between ... and ...的時候我就決定用她了,由於範圍的意思就是between ... and ... 。言下之意就是between and就是範圍,範圍就是between and是多麼【天然】的一件事情。其實我挺喜歡天然這個詞的。在惱羞成怒的狀態下,我拋出了殺手鐗:你知道Junit的assert方法第一個參數是actual仍是第二個參數是actual麼?(畫外音:由於Junit的這些只有兩個參數的assert方法,兩個參數類型是同樣的,我每次使用的時候都搞不清楚第一個是actual仍是expected,若是用錯最後的錯誤提示也是反的,幸虧Junit如今提供了assertThat的方式)。可是他竟然記得,他果斷地說第一個是expected,第二個參數是actual。看來記憶力很差是硬傷,世上總有些人比你記憶力好,他們記得全部東西,因此千萬不要跟他們拼記憶。併發
那麼說了這麼多我想表達什麼呢?我可不是爲了吐槽我那可憐的記憶力的。其實上面兩個例子只是想說,咱們在編寫代碼的時候,應該時刻記着如何編寫明顯沒有錯誤的代碼。在性能沒有量級的不一樣以前,咱們更應該編寫明顯沒有錯誤的代碼(好比剛纔那個查找一天訂單的問題我以爲SELECT order_no FROM orders WHERE create_time like '2015-04-07%'是個更直觀的寫法,可是這種寫法可能性能很差,因此只能做罷)。明顯沒有錯誤的代碼就是即便別人來維護這個代碼的時候缺乏一些上下文信息(好比當前數據庫使用的是什麼精度,或者某方面的知識)都能很容易判斷這個代碼表達的是什麼意思,由於當前他所看到的代碼就是全部的上下文,沒有其餘隱藏的。咱們在編寫代碼的時候必定要記着咱們不是一我的在戰鬥,你的代碼除了機器執行外會有更多的人來閱讀和修改。在我看來SQL的between ... and ...和Junit的assert序列方法都是反面教材,他要靠人們對某些知識的記憶才能理解,但人的記憶又每每很不靠譜,就這樣bug就出現了。即便在有些地方咱們須要進行性能優化,可能把一些代碼給弄得比較難以理解,那麼咱們也應該將這樣的代碼範圍控制好,侷限在某個部分。好比咱們將這樣的代碼封裝到一個類裏,而不是分散到各個地方,而且咱們用類名,用方法名,再不濟用一些註釋向後來者述說着這裏曾經的故事。高併發
大部分開發人員(包括我本身),可能對性能優化更感興趣。好比常見討論方式是:這個地方我去掉了一個鎖,那個地方我減小了多少內存,性能提升了多少多少。而不多見到這樣的討論:這個地方我修改了一個方法名那個地方我修改了一個變量名,如今個人代碼更易懂,更【形象】起來了。其實在一個工程化的環境中,性能是否是重要呢?固然重要,但不是最重要的。而代碼質量纔是提升總體效率,下降故障率更有效的途徑。並且更加諷刺的是,每每咱們的性能到了須要優化的時候了,可是由於代碼實在太糟糕而不知道如何優化,由於看不懂,不敢改。各個地方各類隱藏的上下文,各類歧義代碼讓性能優化難於上青天。你以爲修改這個地方好像沒有問題,可是等你修改以後一個故障就開始了。性能
還有一些開發人員可能比較喜歡遵循本身固有的一些習慣。誠然,每一個人都有一些習慣,多是很早以前在某個角落看到一段什麼話,而後就記下來了,後來一直遵循着這種習慣,可是又說不出真正什麼理由(嗯,就是喜歡)。可是,咱們在遵循這個習慣的時候,也要想着這是個人習慣,不是別人的。這個代碼有沒有更好的寫法呢?全部人一看就知道是這個意思的代碼或許比習慣更重要。優化
因此對我來說,我雖然也很熱衷性能優化,喜歡研究一些所謂的高併發高性能,可是我更想把個人代碼寫得【漂亮】,讓別人維護起來的時候更容易看懂。編寫明顯沒有錯誤的代碼不是一件很LOW的事情,雖然逼格不高。設計