2016-03-07 53 views
2

這個例子,當直覺預計「富巴」的空間,展示了奇怪的行爲:失去在文本轉換

SELECT 'foo'|| '#'::char ||'bar'   -- char ok, foo#bar 
SELECT 'foo'|| '#' ||'bar'    -- literal ok 
SELECT 'foo'|| '#'::text ||'bar'   -- text ok 

SELECT 'foo'|| ' '::char ||'bar'   -- STRANGE! LOSTING SPACE! 
SELECT ('foo'|| ' '::char ||'bar')='foobar' -- yes, it is true... strange 

SELECT 'foo'|| ' '::text ||'bar'   -- text OK 
SELECT 'foo'|| (' '::char)::text ||'bar' -- char-to-text lost! 
SELECT 'foo'|| ' ' ||'bar'    -- literal OK 

爲什麼PostgreSQL的做到這一點?這並不直觀,並且似乎容易出錯。 PS:PostgreSQL指南在哪裏說(它需要紅色警​​報)?

+1

尾隨空格被視爲語義無關緊要,並且在比較兩個字符類型值時忽略了 。 http://www.postgresql.org/docs/current/static/datatype-character.html –

+0

感謝@JakubKania,您在指南(!)中找到了一些內容。那麼,讓我們來說說「指導經理」來**紅色**這些隱藏的評論:-) –

回答

4

這是許多原因之一,因此經常建議堅持使用varchar()或使用Postgres text類型。

SQL標準要求CHAR()值填充空格以填充剩餘的字節。例如:

'A'::CHAR(5) 

將導致"A "被存儲。現在,如果有不同長度的另一個領域,但同樣的內容:

'A'::CHAR10 = 'A'::CHAR(5) 

我們想這樣說TRUE,對不對?因此填充填充CHAR()的空間必須被修剪。

這是一個Postgres的問題,那麼它是一個磁盤存儲或sql標準問題。必須寫入磁盤上的這些字節,標準爲space。有些數據庫只用於比較或轉換,其他的像Postgres,幾乎可以修剪任何功能。

由於您正在將空間轉換爲CHAR(1)(1表示沒有指定默認長度時,儘管對於此問題無關緊要),但您的空間將作爲填充而丟失。這只是使用CHAR()的一個注意事項。如果你這樣做,這是一個該死的,如果你不這樣做,該死的。

取而代之的是把它扔到VARCHAR()TEXT,因爲它們幾乎總是優於CHAR()的類型。

PostgreSQL文檔中注意到:

提示:使用空白填充型時,和一個 幾個額外的CPU週期以從增加的存儲空間有這三種類型之間沒有性能差異,除了 在存儲到長度受限的列中時檢查長度。儘管字符(n)在其他一些數據庫系統中具有很好的性能,但在PostgreSQL中不存在這樣的優勢 ;事實上,字符(n)通常是三個中最慢的,因爲它額外的存儲成本和較慢的排序。在 大多數情況下應該使用文本或字符變化。

+0

謝謝,很好的解釋(!)。嗯...關於PostgreSQL,它不是[KISS](https://en.wikipedia.org/wiki/KISS_principle)項目決定......似乎一些「傳統解決方法」,在pg9 +時下沒有意義,並且這個parse-spaces與任何CPU優化都有最簡單的內部表示相反......您將展示爲什麼* text *數據類型是最簡單的。關於pg-guide,讓我們對「指導經理」說**把* char *數據類型的這些隱藏奇怪的意外行爲置入紅色。 –

+0

不過,我不認爲這些是「奇怪的」。 'CHAR()'在每個RDBMS中都有各種注意事項,這些注意事項都歸結爲必要的填充以填充磁盤上的字節。這不是一個CPU問題,而是一個數據存儲問題,然後導致增加的CPU,因爲每次對'CHAR()'類型字段應用操作時都必須進行修整。通常'char()'的唯一好處是已知長度字段的磁盤空間減少了,但我們談論的是1到4個字節,減去壓縮,所以它真的不值得。 – JNevill

+0

再次好解釋;-)謝謝。關於「奇怪」是個人觀點,我認爲「字符串類型」的*正交性是最重要的,它簡化了一些20世紀90年代的應用/優化......今天,混淆的風險(在開發/支持團隊中)我的意見,失去了任何使用'char()'數據類型。 –