2010-08-11 250 views
3

假設我有一個列name varchar(20)的表,我存儲了一行name =「abcdef」。這不會使varchar2效率低下?

INSERT INTO tab(id, name) values(12, 'abcdef'); 

如何爲name內存分配在這種情況下怎麼辦?

有兩種方法我能想到的:

一)

20字節分配,但只用6。就內存分配而言,在這種情況下,varchar2char相比沒有任何顯着優勢。

B)

只有6個字節被分配。如果是這樣的話,我addded一對夫婦更行這一個之後,

INSERT INTO tab(id, name) values(13, 'yyyy'); 
INSERT INTO tab(id, name) values(14, 'zzzz'); 

,然後我做了更新,

UPDATE tab SET name = 'abcdefghijkl' WHERE id = 12; 

哪裏的DBMS獲取所需的額外6個字節從?可能存在下一個6字節不空閒的情況(如果最初僅分配了6個字節,則可能已經爲其他字節分配了下一個字節)。

除了將排移到新位置之外,還有別的方法嗎?即使移位也會成爲索引組織表格的問題(對於堆組織的表格來說可能沒問題)。

+1

這是依賴於實現的,但很可能當您更新時,新行將寫入與舊行完全不同的位置。即使沒有varchar也是如此。 – hobbs 2010-08-11 09:26:48

回答

1

有可能取決於你所使用的RDBMS的變化,但一般:

只有你在varchar現場存儲的實際數據進行分配。大小隻是允許的最大值,並不是分配多少。

我認爲這也適用於char字段,在某些系統上。可變大小數據類型的處理效率足夠高,以至於在分配最大值時不再有任何收益。

如果更新記錄以使其需要更多空間,則同一分配塊內的記錄向下移動,如果記錄不再適合該塊,則分配另一個塊並將記錄分配到塊之間。這意味着記錄在分配塊內是連續的,但塊不必在磁盤上連續。

+0

在Oracle和DB2系統上,NOT NULL CHAR(n BYTES)字段將始終消耗n個字節。 – 2010-08-12 17:36:35

1

它當然不會分配更多的空間,然後需要,這將打敗使用可變長度類型的點。

在你提到的情況下,我會認爲下面的行將不得不在頁面上向下移動,或許這是優化的。我真的不知道確切的細節,也許別人可以進一步評論。

1

編輯出於某種原因,我認爲這被標記爲Microsoft SQL Server。我想答案仍然是相關的,雖然

這就是爲什麼official recommendation

  • 使用CHAR時,列數據項的大小是一致的。
  • 當列數據條目的大小相差很大時,使用varchar。
  • 當列數據條目的大小變化很大時,使用varchar(max),大小可能爲 超過8,000字節。

這是在設計表結構時需要考慮的因素。可能你需要考慮在這個計算中更新vs讀取的頻率太

值得注意的是,對於char a NULL值仍然使用所有的存儲空間。 Management Studio中有一個名爲SQL Internals Viewer的插件,可讓您輕鬆查看行的存儲方式。

1

這可能嚴重依賴數據庫。

雖然有幾點:MVCC觀察數據庫實際上並未更新磁盤或內存高速緩存中的數據。他們用更新的數據插入一個新行,並將舊行標記爲從某個事務中刪除。過了一段時間後,刪除的行對任何事務都不可見並且被回收。

對於存儲空間問題,它通常是在的1-4 bytes of header + data (+ padding)

在字符的情況下的形式,該數據被填充以達到足夠的長度。在varchar或text的情況下,標題存儲了後續數據的長度。

+0

您對MVCC數據庫的工作方式的描述與Oracle的工作方式不一致。 Oracle會在適當位置更新該行,同時編寫信息以撤銷回滾段或撤消表中的更改,以便可以讀取以前的版本。以及寫入重做日誌,以便在發生故障時不會丟失更改。 – 2010-08-16 19:43:39

1

鑑於問題標題中的VARCHAR2,我假設您的問題集中在Oracle。在Oracle中,可以使用PCTFREE子句爲數據塊內的行擴展保留空間。這可以幫助減輕更新使行更長的影響。但是,如果Oracle在塊內沒有足夠的可用空間來寫回行,則它所做的操作稱爲行遷移;它只在磁盤上留下原始地址(因此它不一定需要更新索引),但不是將數據存儲在原始位置,而是存儲指向該行新地址的指針。

如果大量的行已遷移,那麼在索引嚴重訪問表的情況下,這會導致性能問題,因爲它會添加額外的I/O以滿足查詢。