資料類型
原生類型
CQL 支援的原生類型為
native_type::= ASCII | BIGINT | BLOB | BOOLEAN | COUNTER | DATE
| DECIMAL | DOUBLE | DURATION | FLOAT | INET | INT |
SMALLINT | TEXT | TIME | TIMESTAMP | TIMEUUID | TINYINT |
UUID | VARCHAR | VARINT | VECTOR
下表提供原生資料類型的其他資訊,以及每種類型支援的 常數 類型
類型 | 支援的常數 | 說明 |
---|---|---|
|
|
ASCII 字元字串 |
|
|
64 位元有號長整數 |
|
|
任意位元組 (無驗證) |
|
|
|
|
|
計數器欄位 (64 位元有號值)。有關詳細資訊,請參閱 |
|
|
日期 (沒有對應的時間值)。有關詳細資訊,請參閱下方的 |
|
|
可變精度的十進位數 |
|
|
64 位元 IEEE-754 浮點數 |
|
|
具有奈秒精度的持續時間。有關詳細資訊,請參閱下方的 |
|
|
32 位元 IEEE-754 浮點數 |
|
|
IP 位址,可能是 IPv4 (4 位元組長) 或 IPv6 (16 位元組長)。請注意,沒有 |
|
|
32 位元有號整數 |
|
|
16 位元有號整數 |
|
|
UTF8 編碼字串 |
|
|
時間(無對應日期值),精確到奈秒。詳情請參閱下方 |
|
|
時間戳記(日期和時間),精確到毫秒。詳情請參閱下方 |
|
|
版本 1 UUID,通常用作「無衝突」時間戳記。另請參閱 |
|
|
8 位元有號整數 |
|
|
UUID(任何版本) |
|
|
UTF8 編碼字串 |
|
|
任意精度的整數 |
|
|
定長非空陣列,包含浮點值 CASSANDRA-18504 將此資料類型新增至 Cassandra 5.0。 |
計數器
counter
類型用於定義計數器欄位。計數器欄位是一個欄位,其值為 64 位元有號整數,且支援兩個運算:遞增和遞減(語法請參閱 UPDATE 陳述式)。請注意,無法設定計數器的值:計數器在第一次遞增/遞減之前不存在,而第一次遞增/遞減會視為先前的值為 0。
計數器有許多重要的限制
使用時間戳記
timestamp
類型的值編碼為 64 位元有號整數,代表自稱為 Epoch 時間 的標準基準時間(1970 年 1 月 1 日格林威治標準時間 00:00:00)開始經過的毫秒數。
時間戳記可以在 CQL 中輸入,使用其值作為 integer
,或使用代表 ISO 8601 日期格式的 string
。例如,以下所有值都是 2011 年 3 月 2 日格林威治標準時間上午 04:05:00 AM 的有效 timestamp
值
-
1299038700000
-
'2011-02-03 04:05+0000'
-
'2011-02-03 04:05:00+0000'
-
'2011-02-03 04:05:00.000+0000'
-
'2011-02-03T04:05+0000'
-
'2011-02-03T04:05:00+0000'
-
'2011-02-03T04:05:00.000+0000'
上述的 +0000
是 RFC 822 4 位元時區規格;+0000
指的是格林威治標準時間。美國太平洋標準時間是 -0800
。時區可以省略('2011-02-03 04:05:00'
),如果是這樣,日期會被解釋為協調的 Cassandra 節點設定的時區。然而,依賴於預期的時區設定是有其困難度的,因此建議在可行的情況下,總是為時間戳記指定時區。
也可以省略時間('2011-02-03'
或 '2011-02-03+0000'
),這種情況下,時間會預設為指定或預設時區的 00:00:00。但是,如果只有日期部分相關,請考慮使用 date 類型。
日期類型
date
類型的值編碼為 32 位元無號整數,代表自範圍中心(2^31)的「Epoch 時間」開始經過的天數。Epoch 時間為 1970 年 1 月 1 日
對於 時間戳記,日期可以輸入為 integer
或使用日期 string
。在後者的情況下,格式應為 yyyy-mm-dd
(例如 '2011-02-03'
)。
時間類型
time
類型的值編碼為 64 位元有號整數,代表自午夜開始經過的奈秒數。
對於 時間戳記,時間可以輸入為 整數
或使用表示時間的 字串
。在後面的情況中,格式應為 hh:mm:ss[.fffffffff]
(其中次秒精度是可選的,如果提供,可以小於納秒)。因此,例如,以下是時間的有效輸入
-
'08:12:54'
-
'08:12:54.123'
-
'08:12:54.123456'
-
'08:12:54.123456789'
持續時間類型
持續時間
類型的值編碼為 3 個可變長度的有號整數。第一個整數表示月份數,第二個整數表示天數,第三個整數表示納秒數。這是因為一個月中天數會改變,而一天可以有 23 或 25 小時,具體取決於夏令時。在內部,月份和天數被解碼為 32 位元組整數,而納秒數被解碼為 64 位元組整數。
持續時間可以輸入為
-
(數量單位)+
例如12h30m
,其中單位可以是-
y
:年(12 個月) -
mo
:月(1 個月) -
w
:週(7 天) -
d
:天(1 天) -
h
:小時(3,600,000,000,000 納秒) -
m
:分鐘(60,000,000,000 納秒) -
s
:秒(1,000,000,000 納秒) -
ms
:毫秒(1,000,000 納秒) -
us
或µs
:微秒(1000 納秒) -
ns
:納秒(1 納秒)
-
-
ISO 8601 格式:
P[n]Y[n]M[n]DT[n]H[n]M[n]S 或 P[n]W
-
ISO 8601 替代格式:
P[YYYY]-[MM]-[DD]T[hh]:[mm]:[ss]
例如
INSERT INTO RiderResults (rider, race, result)
VALUES ('Christopher Froome', 'Tour de France', 89h4m48s);
INSERT INTO RiderResults (rider, race, result)
VALUES ('BARDET Romain', 'Tour de France', PT89H8M53S);
INSERT INTO RiderResults (rider, race, result)
VALUES ('QUINTANA Nairo', 'Tour de France', P0000-00-00T89:09:09);
持續時間欄不能用於表格的 PRIMARY KEY
。此限制是因為持續時間無法排序。在沒有日期上下文的情況下,實際上無法知道 1mo
是否大於 29d
。
1d
持續時間不等於 24h
持續時間,因為持續時間類型被創建為能夠支援夏令時。
集合
CQL 支援三種類型的集合:映射
、集合
和 清單
。這些集合的類型由
collection_type::= MAP '<' cql_type',' cql_type'>'
| SET '<' cql_type '>'
| LIST '<' cql_type'>'
定義,其值可以使用集合文字輸入
collection_literal::= map_literal | set_literal | list_literal
map_literal::= '\{' [ term ':' term (',' term : term)* ] '}'
set_literal::= '\{' [ term (',' term)* ] '}'
list_literal::= '[' [ term (',' term)* ] ']'
但請注意,集合文字中不支援 bind_marker
或 NULL
。
值得注意的特徵
集合用於儲存/反正規化相對較少量的資料。它們適用於「給定使用者的電話號碼」、「應用於電子郵件的標籤」等事物。但是,當預期項目會無限增加(「使用者傳送的所有訊息」、「感測器註冊的事件」……)時,集合就不適用了,應該使用特定表格(含分群欄位)。具體來說,(未凍結)集合具有下列值得注意的特徵和限制
-
個別集合在內部沒有索引。這表示即使要存取集合的單一元素,也必須讀取整個集合(而且在內部讀取一個集合不會分頁)。
-
雖然對集合和映射的插入作業在內部從不發生寫入前讀取,但對清單的某些作業會發生。此外,某些清單作業本質上不是冪等(請參閱下方 清單 區段的詳細資料),這會讓它們在逾時時重試變得有問題。因此,建議在可能的情況下優先使用集合而非清單。
請注意,雖然有些限制未來可能會移除或改善,但使用(單一)集合來儲存大量資料是一種反模式。
映射
map
是(已排序)的鍵值對集合,其中鍵是唯一的,且映射依其鍵排序。您可以使用下列方式定義和插入映射
CREATE TABLE users (
id text PRIMARY KEY,
name text,
favs map<text, text> // A map of text keys, and text values
);
INSERT INTO users (id, name, favs)
VALUES ('jsmith', 'John Smith', { 'fruit' : 'Apple', 'band' : 'Beatles' });
// Replace the existing map entirely.
UPDATE users SET favs = { 'fruit' : 'Banana' } WHERE id = 'jsmith';
此外,映射支援
-
更新或插入一個或多個元素
UPDATE users SET favs['author'] = 'Ed Poe' WHERE id = 'jsmith'; UPDATE users SET favs = favs + { 'movie' : 'Cassablanca', 'band' : 'ZZ Top' } WHERE id = 'jsmith';
-
移除一個或多個元素(如果元素不存在,移除它是不執行任何作業,但不會擲回錯誤)
DELETE favs['author'] FROM users WHERE id = 'jsmith'; UPDATE users SET favs = favs - { 'movie', 'band'} WHERE id = 'jsmith';
請注意,對於移除
map
中的多個元素,您會從中移除一個鍵的set
。
最後,INSERT
和 UPDATE
都允許 TTL,但在兩種情況下,設定的 TTL 僅適用於新插入/更新的元素。換句話說
UPDATE users USING TTL 10 SET favs['color'] = 'green' WHERE id = 'jsmith';
只會將 TTL 套用於 { 'color' : 'green' }
記錄,映射的其餘部分不受影響。
集合
set
是(已排序)的唯一值集合。您可以使用下列方式定義和插入集合
CREATE TABLE images (
name text PRIMARY KEY,
owner text,
tags set<text> // A set of text values
);
INSERT INTO images (name, owner, tags)
VALUES ('cat.jpg', 'jsmith', { 'pet', 'cute' });
// Replace the existing set entirely
UPDATE images SET tags = { 'kitten', 'cat', 'lol' } WHERE name = 'cat.jpg';
此外,集合支援
-
新增一個或多個元素(因為這是集合,所以插入已存在的元素是不執行任何作業)
UPDATE images SET tags = tags + { 'gray', 'cuddly' } WHERE name = 'cat.jpg';
-
移除一個或多個元素(如果元素不存在,移除它是一個空操作,但不會擲回錯誤)
UPDATE images SET tags = tags - { 'cat' } WHERE name = 'cat.jpg';
最後,對於 集合,TTL 僅套用於新插入的值。
串列
如上所述,並在本節的最後進一步討論,串列有其限制和特定的效能考量,在使用它們之前,您應該將這些考量納入考量。一般來說,如果您能使用 集合 代替串列,請務必優先選擇集合。 |
串列
是非唯一值的(已排序)集合,其中元素依其在串列中的位置排序。您可以使用下列方式定義和插入串列
CREATE TABLE plays (
id text PRIMARY KEY,
game text,
players int,
scores list<int> // A list of integers
)
INSERT INTO plays (id, game, players, scores)
VALUES ('123-afde', 'quake', 3, [17, 4, 2]);
// Replace the existing list entirely
UPDATE plays SET scores = [ 3, 9, 4] WHERE id = '123-afde';
此外,串列支援
-
將值附加到串列的尾端和前端
UPDATE plays SET players = 5, scores = scores + [ 14, 21 ] WHERE id = '123-afde'; UPDATE plays SET players = 6, scores = [ 3 ] + scores WHERE id = '123-afde';
警告
附加和預先附加操作本質上並非冪等。因此,特別是如果其中一個操作逾時,則重試該操作並不安全,而且它可能會(或可能不會)導致附加/預先附加值兩次。 |
-
設定串列中特定位置的值,該位置有預先存在的元素。如果串列沒有該位置,將擲回錯誤
UPDATE plays SET scores[1] = 7 WHERE id = '123-afde';
-
移除串列中特定位置的元素,該位置有預先存在的元素。如果串列沒有該位置,將擲回錯誤。此外,由於操作會從串列中移除元素,因此串列大小將減少一個元素,將所有後續元素的位置向前移動一個
DELETE scores[1] FROM plays WHERE id = '123-afde';
-
刪除串列中特定值所有的出現(如果特定元素根本沒有出現在串列中,它只會被忽略,而且不會擲回錯誤)
UPDATE plays SET scores = scores - [ 12, 21 ] WHERE id = '123-afde';
警告
依位置設定和移除元素,以及移除特定值的出現,會產生內部讀取再寫入。這些操作執行速度會很慢,而且會比一般的更新使用更多資源(排除條件式寫入,條件式寫入有其自己的成本)。 |
最後,對於 串列,TTL 僅套用於新插入的值。
使用向量
向量是特定資料類型非空值的固定大小序列。它們使用與串列相同的字面值。
您可以使用下列方式定義、插入和更新向量
CREATE TABLE plays (
id text PRIMARY KEY,
game text,
players int,
scores vector<int, 3> // A vector of 3 integers
)
INSERT INTO plays (id, game, players, scores)
VALUES ('123-afde', 'quake', 3, [17, 4, 2]);
// Replace the existing vector entirely
UPDATE plays SET scores = [ 3, 9, 4] WHERE id = '123-afde';
請注意,無法變更向量的個別值,而且無法選取向量的個別元素。
使用者定義類型 (UDT)
CQL 支援使用者定義類型 (UDT) 的定義。此類型的建立、修改和移除可以使用下面所述的 create_type_statement
、alter_type_statement
和 drop_type_statement
。
user_defined_type::= udt_name
udt_name::= [ keyspace_name '.' ] identifier
建立 UDT
建立新的使用者定義類型是使用 CREATE TYPE
陳述式,定義如下
create_type_statement::= CREATE TYPE [ IF NOT EXISTS ] udt_name
'(' field_definition ( ',' field_definition)* ')'
field_definition::= identifier cql_type
UDT 有名稱(用於宣告該類型的欄位)和一組已命名且已鍵入的欄位。欄位名稱可以是任何類型,包括集合或其他 UDT。例如
CREATE TYPE phone (
country_code int,
number text,
);
CREATE TYPE address (
street text,
city text,
zip text,
phones map<text, phone>
);
CREATE TABLE user (
name text PRIMARY KEY,
addresses map<text, frozen<address>>
);
關於 UDT 應注意的事項
-
嘗試建立已存在的類型會導致錯誤,除非使用
IF NOT EXISTS
選項。如果使用,如果類型已存在,陳述式將不會執行任何操作。 -
類型本質上與其建立的鍵集空間繫結,而且只能在該鍵集空間中使用。建立時,如果類型名稱加上鍵集空間名稱的前置詞,則會在該鍵集空間中建立。否則,會在目前的鍵集空間中建立。
-
自 Cassandra 起,UDT 在大多數情況下必須凍結,因此在上面的表格定義中有
frozen<address>
。
UDT 文字
建立使用者定義類型後,可以使用 UDT 文字輸入值
udt_literal::= '{' identifier ':' term ( ',' identifier ':' term)* '}'
換句話說,UDT 文字就像 映射` 文字,但其金鑰是類型的欄位名稱。例如,可以使用以下方式插入到前一節中定義的表格中
INSERT INTO user (name, addresses)
VALUES ('z3 Pr3z1den7', {
'home' : {
street: '1600 Pennsylvania Ave NW',
city: 'Washington',
zip: '20500',
phones: { 'cell' : { country_code: 1, number: '202 456-1111' },
'landline' : { country_code: 1, number: '...' } }
},
'work' : {
street: '1600 Pennsylvania Ave NW',
city: 'Washington',
zip: '20500',
phones: { 'fax' : { country_code: 1, number: '...' } }
}
}
);
要有效,UDT 文字只能包含其文字所屬類型的定義欄位,但可以省略一些欄位(這些欄位將設為 NULL
)。
變更 UDT
可以使用 ALTER TYPE
陳述式修改現有的使用者定義類型
alter_type_statement::= ALTER TYPE [ IF EXISTS ] udt_name alter_type_modification
alter_type_modification::= ADD [ IF NOT EXISTS ] field_definition
| RENAME [ IF EXISTS ] identifier TO identifier (AND identifier TO identifier )*
如果類型不存在,陳述式將傳回錯誤,除非使用 IF EXISTS
,這種情況下,操作不會執行任何操作。您可以
-
新增新欄位到類型(
ALTER TYPE address ADD country text
)。對於在新增之前建立的任何類型值,該新欄位將為NULL
。如果新欄位存在,陳述式將傳回錯誤,除非使用IF NOT EXISTS
,這種情況下,操作不會執行任何操作。 -
重新命名類型的欄位。如果欄位不存在,陳述式將傳回錯誤,除非使用
IF EXISTS
,這種情況下,操作不會執行任何操作。
ALTER TYPE address RENAME zip TO zipcode;
組
CQL 也支援組和組類型(其中元素可以是不同類型)。在功能上,組可以視為具有匿名欄位的匿名 UDT。組類型和組文字定義如下
tuple_type::= TUPLE '<' cql_type( ',' cql_type)* '>'
tuple_literal::= '(' term( ',' term )* ')'
,並且可以建立如下
CREATE TABLE durations (
event text,
duration tuple<int, text>,
);
INSERT INTO durations (event, duration) VALUES ('ev1', (3, 'hours'));
與其他複合類型(例如集合和 UDT)不同,組總是 frozen <frozen>
(不需要 frozen
關鍵字),而且不可能只更新組的某些元素(而不更新整個組)。此外,組文字的數值應該總是與其所屬類型的宣告數值相同(其中一些數值可以為 null,但需要明確宣告為 null)。
自訂類型
自訂類型主要存在於向後相容性的目的,不建議使用。它們的使用很複雜,對使用者不友善,而且其他提供的類型,特別是 使用者定義類型,幾乎總是足夠的。 |
自訂類型定義如下
custom_type::= string
自訂類型是一個 string
,其中包含延伸伺服器端 AbstractType
類別的 Java 類別名稱,而且 Cassandra 可以載入(因此它應該在執行 Cassandra 的每個節點的 CLASSPATH
中)。該類別將定義哪些值對類型有效,以及在用於叢集欄位時時間如何排序。對於任何其他目的,自訂類型的值與 blob
的值相同,特別是可以使用 blob
文字語法輸入。