CQL3 is the newly ordained, canonical, and best-practices means of interacting with Cassandra. Indeed, the Apache Cassandra documentation itself declares that the Thrift API as “legacy” and recommends that CQL3 be used instead. But I’ve heard several people express their concern over the added layer of abstraction. There seems to be an uncertainty about what’s really happening inside of Cassandra.
In this presentation we will open up the hood and take a look at exactly how Cassandra is treating CQL3 queries. Our first stop will be the Cassandra data structure itself. We will briefly review the concepts of keyspaces, columnfamilies, rows, and columns. And we will explain where this data structure excels and where it does not. Composite rowkeys and columnnames are heavily used with CQL3, so we'll cover their functionality as well.
We will then turn to CQL3. I will demonstrate the basic CQL syntax and show how it maps to the underlying data structure. We will see that CQL actually serves as a sort of best practices interface to the internal Cassandra data structure. We will take this point further by demonstrating CQL3 collections (set, list, and map) and showing how they are really just a creative use of this same internal data structure.
Attendees will leave with a clear, inside-out understanding of CQL3 and will be able use CQL with a confidence that they are following best-practices.
2. Outline
•
•
•
•
•
•
•
What Problem does CQL Solve?
The Cassandra Data Model
Pain Points of “Old” Cassandra
Introducing CQL
Understanding the CQL/Cassandra Mapping
CQL for Sets, Lists, and Maps
Putting it All Together
OpenSource Connections
3. What Problem does CQL Solve?
• The Awesomeness that is Cassandra:
o
o
o
o
o
o
Distributed columnar data store
No single point of failure
Optimized for availability (though “Tunably” consistent)
Optimized for writes
Easily maintainable
Almost infinitely scalable
.
OpenSource Connections
4. What Problem does CQL Solve?
• The Awesomeness that is Cassandra:
o
o
o
o
o
o
Distributed columnar data store
No single point of failure
Optimized for availability (though “Tunably” consistent)
Optimized for writes
Easily maintainable
Almost infinitely scalable
• Cassandra’s usability challenges
o NoSQL – “Where are my JOINS? No Schema? De-normalize!?”
o BigTable – “Tables with millions of columns!?”
.
OpenSource Connections
5. What Problem does CQL Solve?
• The Awesomeness that is Cassandra:
o
o
o
o
o
o
Distributed columnar data store
No single point of failure
Optimized for availability (though “Tunably” consistent)
Optimized for writes
Easily maintainable
Almost infinitely scalable
• Cassandra’s usability challenges
o NoSQL – “Where are my JOINS? No Schema? De-normalize!?”
o BigTable – “Tables with millions of columns!?”
• CQL saves the day!
o A best-practices interface to Cassandra
o Uses familiar SQL-like language
OpenSource Connections
11. C* Data Model
Row Key
Column
Column Name
Column Value
(or Tombstone)
Timestamp
Time-to-live
OpenSource Connections
12. C* Data Model
Row Key
Column
Column Name
Column Value
(or Tombstone)
Timestamp
Time-to-live
● Row Key, Column Name, Column
Value have types
● Column Name has comparator
● RowKey has partitioner
● Rows can have any number of
columns - even in same column family
● Rows can have many columns
● Column Values can be omitted
● Time-to-live is useful!
● Tombstones
OpenSource Connections
13. C* Data Model: Writes
Mem
Table
CommitLog
Row
Cache
Bloom
Filter
● Insert into
MemTable
● Dump to
CommitLog
● No read
● Very Fast!
● Blocks on CPU
before O/I!
Key
Cache
Key
Cache
Key
Cache
Key
Cache
SSTable
SSTable
SSTable
SSTable
OpenSource Connections
14. C* Data Model: Writes
Mem
Table
CommitLog
Row
Cache
Bloom
Filter
● Insert into
MemTable
● Dump to
CommitLog
● No read
● Very Fast!
● Blocks on CPU
before O/I!
Key
Cache
Key
Cache
Key
Cache
Key
Cache
SSTable
SSTable
SSTable
SSTable
OpenSource Connections
15. C* Data Model: Writes
Mem
Table
CommitLog
Row
Cache
Bloom
Filter
● Insert into
MemTable
● Dump to
CommitLog
● No read
● Very Fast!
● Blocks on CPU
before O/I!
Key
Cache
Key
Cache
Key
Cache
Key
Cache
SSTable
SSTable
SSTable
SSTable
OpenSource Connections
16. C* Data Model:
Reads
Mem
Table
CommitLog
Row
Cache
Bloom
Filter
● Get values from Memtable
● Get values from row
cache if present
● Otherwise check bloom
filter to find appropriate
SSTables
● Check Key Cache for fast
SSTable Search
● Get values from SSTables
● Repopulate Row Cache
● Super Fast Col. retrieval
● Fast row slicing
Key
Cache
Key
Cache
Key
Cache
Key
Cache
SSTable
SSTable
SSTable
SSTable
OpenSource Connections
17. C* Data Model:
Reads
Mem
Table
CommitLog
Row
Cache
Bloom
Filter
● Get values from Memtable
● Get values from row
cache if present
● Otherwise check bloom
filter to find appropriate
SSTables
● Check Key Cache for fast
SSTable Search
● Get values from SSTables
● Repopulate Row Cache
● Super Fast Col. retrieval
● Fast row slicing
Key
Cache
Key
Cache
Key
Cache
Key
Cache
SSTable
SSTable
SSTable
SSTable
OpenSource Connections
18. C* Data Model:
Reads
Mem
Table
CommitLog
Row
Cache
Bloom
Filter
● Get values from Memtable
● Get values from row
cache if present
● Otherwise check bloom
filter to find appropriate
SSTables
● Check Key Cache for fast
SSTable Search
● Get values from SSTables
● Repopulate Row Cache
● Super Fast Col. retrieval
● Fast row slicing
Key
Cache
Key
Cache
Key
Cache
Key
Cache
SSTable
SSTable
SSTable
SSTable
OpenSource Connections
19. C* Data Model:
Reads
Mem
Table
CommitLog
Row
Cache
Bloom
Filter
● Get values from Memtable
● Get values from row
cache if present
● Otherwise check bloom
filter to find appropriate
SSTables
● Check Key Cache for fast
SSTable Search
● Get values from SSTables
● Repopulate Row Cache
● Super Fast Col. retrieval
● Fast row slicing
Key
Cache
Key
Cache
Key
Cache
Key
Cache
SSTable
SSTable
SSTable
SSTable
OpenSource Connections
20. C* Data Model:
Reads
Mem
Table
CommitLog
Row
Cache
Bloom
Filter
● Get values from Memtable
● Get values from row
cache if present
● Otherwise check bloom
filter to find appropriate
SSTables
● Check Key Cache for fast
SSTable Search
● Get values from SSTables
● Repopulate Row Cache
● Super Fast Col. retrieval
● Fast row slicing
Key
Cache
Key
Cache
Key
Cache
Key
Cache
SSTable
SSTable
SSTable
SSTable
OpenSource Connections
21. C* Data Model:
Reads
Mem
Table
CommitLog
Row
Cache
Bloom
Filter
● Get values from Memtable
● Get values from row
cache if present
● Otherwise check bloom
filter to find appropriate
SSTables
● Check Key Cache for fast
SSTable Search
● Get values from SSTables
● Repopulate Row Cache
● Super Fast Col. retrieval
● Fast row slicing
Key
Cache
Key
Cache
Key
Cache
Key
Cache
SSTable
SSTable
SSTable
SSTable
OpenSource Connections
22. Cassandra Pain Points
• Twitter Example
• My tweets
o SET tweets[JnBrymn][2013-07-19 T 09:20] = “Wonderful
morning. This coffee is great.”
o SET tweets[JnBrymn][2013-07-19 T 09:21] = “Oops, smoke is
coming out of the SQL server!”
o SET tweets[JnBrymn][2013-07-19 T 09:51] = “Now my coffee is
cold :-(”
• Get John’s tweets
o GET tweets[JnBrymn]
(output is as expected)
OpenSource Connections
23. Cassandra Pain Points
• Twitter Example
• My tweets
o SET tweets[JnBrymn][2013-07-19 T 09:20] = “Wonderful
morning. This coffee is great.”
o SET tweets[JnBrymn][2013-07-19 T 09:21] = “Oops, smoke is
coming out of the SQL server!”
o SET tweets[JnBrymn][2013-07-19 T 09:51] = “Now my coffee is
cold :-(”
• Get John’s tweets
o GET tweets[JnBrymn]
(output is as expected)
• Pain-point: schema-less means that you have to
read code to understand data model
OpenSource Connections
24. Cassandra Pain Points
• My timeline (other’s tweets)
• More complicated – must store corresponding user
names
• Bad Option 1: keep multiple column families
o SET timeline_from[JnBrymn][2013-07-19 T 09:20] =
“softwaredoug”
o SET timeline_text[JnBrymn][2013-07-19 T 09:20] = “Hey John I
posted on reddit, upvote me!”
• Get John’s timeline
o GET timeline_from[JnBrymn]
o GET timeline_text[JnBrymn]
OpenSource Connections
25. Cassandra Pain Points
• My timeline (other’s tweets)
• More complicated – must store corresponding user
names
• Bad Option 1: keep multiple column families
o SET timeline_from[JnBrymn][2013-07-19 T 09:20] =
“softwaredoug”
o SET timeline_text[JnBrymn][2013-07-19 T 09:20] = “Hey John I
posted on reddit, upvote me!”
• Get John’s timeline
o GET timeline_from[JnBrymn]
o GET timeline_text[JnBrymn]
• Pain-point: Multiple queries required.
OpenSource Connections
26. Cassandra Pain Points
• My timeline
• Bad Option 2: shove into single column value
o SET timeline[JnBrymn][2013-07-19 T 09:20] =
{from:”softwaredoug”, text: “Hey John I posted on reddit, upvote
me!”
• Get John’s timeline
o GET timeline[JnBrymn] (…not too bad.)
OpenSource Connections
27. Cassandra Pain Points
• My timeline
• Bad Option 2: shove into single column value
o SET timeline[JnBrymn][2013-07-19 T 09:20] =
{from:”softwaredoug”, text: “Hey John I posted on reddit, upvote
me!”
• Get John’s timeline
o GET timeline[JnBrymn] (…not too bad.)
• Pain-point: Updates require a read-then-modify
OpenSource Connections
28. Cassandra Pain Points
• My timeline
• Best Option: composite column names
o SET timeline[JnBrymn][2013-07-19 T 09:20|from] =
”softwaredoug”
o SET timeline[JnBrymn][2013-07-19 T 09:20|text] = “Hey John, I
posted on reddit, upvote me!”
• Get John’s timeline
o GET timeline[JnBrymn] (extract from and text in client)
• Resolves prior pain points! Scales well!
OpenSource Connections
29. Cassandra Pain Points
• My timeline
• Best Option: composite column names
o SET timeline[JnBrymn][2013-07-19 T 09:20|from] =
”softwaredoug”
o SET timeline[JnBrymn][2013-07-19 T 09:20|text] = “Hey John, I
posted on reddit, upvote me!”
• Get John’s timeline
o GET timeline[JnBrymn] (extract from and text in client)
• Resolves prior pain points! Scales well!
• Pain-point: Even more code reading to understand
data model!
OpenSource Connections
30. Cassandra Pain Points
• Justin Bieber’s timeline (e.g. many tweets)
• Previous solution fails if number of columns > 2Billion
• Best Option: composite row names
o SET timeline[bieber|2013-07][19 T 09:20|from] = ”softwaredoug”
o SET timeline[bieber|2013-07][19 T 09:20|text] = “Justin Bieber,
you complete me.”
• Get Justin’s timeline
o GET timeline[bieber|2013-07] (get other months too)
OpenSource Connections
31. Cassandra Pain Points
• Justin Bieber’s timeline (e.g. many tweets)
• Previous solution fails if number of columns > 2Billion
• Best Option: composite row names
o SET timeline[bieber|2013-07][19 T 09:20|from] = ”softwaredoug”
o SET timeline[bieber|2013-07][19 T 09:20|text] = “Justin Bieber,
you complete me.”
• Get Justin’s timeline
o GET timeline[bieber|2013-07] (get other months too)
• Pain-point: Even more code reading to understand
data model!
OpenSource Connections
32. Introducing CQL
• CQL is a reintroduction of schema so that you don’t
have to read code to understand the data model.
• CQL creates a common language so that details of
the data model can be easily communicated.
• CQL is a best-practices Cassandra interface and
hides the messy details.
OpenSource Connections
33. Introducing CQL
• CQL is a reintroduction of schema so that you don’t
have to read code to understand the data model.
• CQL creates a common language so that details of
the data model can be easily communicated.
• CQL is a best-practices Cassandra interface and
hides the messy details.
Let’s see it!
OpenSource Connections
39. Introducing CQL
“Hey sweet! It’s exactly the same as MySQL!”
Hold your horses. There are some
important differences.
OpenSource Connections
40. Introducing CQL
“Hey sweet! It’s exactly the same as MySQL!”
Hold your horses. There are some
important differences.
“Wait? What happened to the
Cassandra’s wide rows?”
OpenSource Connections
41. Introducing CQL
“Hey sweet! It’s exactly the same as MySQL!”
Hold your horses. There are some
important differences.
“Wait? What happened to the
Cassandra’s wide rows?”
There’s still there. Understanding
the mapping is crucial!
OpenSource Connections
42. Introducing CQL
“Hey sweet! It’s exactly the same as MySQL!”
Hold your horses. There are some
important differences.
“Wait? What happened to the
Cassandra’s wide rows?”
There’s still there. Understanding
the mapping is crucial!
Remember this:
•Cassandra finds rows fast
•Cassandra scans columns fast
•Cassandra does not scan rows
OpenSource Connections
44. The CQL/Cassandra Mapping
CREATE TABLE employees (
name text PRIMARY KEY,
age int,
role text
);
name | age | role
-----+-----+----john | 37 | dev
eric | 38 | ceo
OpenSource Connections
45. The CQL/Cassandra Mapping
CREATE TABLE employees (
name text PRIMARY KEY,
age int,
role text
);
age
john
role
37
dev
name | age | role
-----+-----+----john | 37 | dev
eric | 38 | ceo
age
eric
role
38
ceo
OpenSource Connections
46. The CQL/Cassandra Mapping
CREATE TABLE employees (
company text,
name text,
age int,
role text,
PRIMARY KEY (company,name)
);
OpenSource Connections
47. The CQL/Cassandra Mapping
CREATE TABLE employees (
company text,
name text,
age int,
role text,
PRIMARY KEY (company,name)
);
company | name | age | role
--------+------+-----+----OSC | eric | 38 | ceo
OSC | john | 37 | dev
RKG | anya | 29 | lead
RKG | ben | 27 | dev
RKG | chad | 35 | ops
OpenSource Connections
48. The CQL/Cassandra Mapping
company | name | age | role
--------+------+-----+----OSC | eric | 38 | ceo
OSC | john | 37 | dev
RKG | anya | 29 | lead
RKG | ben | 27 | dev
RKG | chad | 35 | ops
CREATE TABLE employees (
company text,
name text,
age int,
role text,
PRIMARY KEY (company,name)
);
eric:age
OS
C
eric:role
john:age
john:role
38
dev
37
dev
anya:age
RK
G
anya:role
ben:age
ben:role
chad:age
chad:role
29
lead
27
dev
35
ops
OpenSource Connections
49. The CQL/Cassandra Mapping
CREATE TABLE example (
A text,
B text,
C text,
D text,
E text,
F text,
PRIMARY KEY ((A,B),C,D)
);
OpenSource Connections
50. The CQL/Cassandra Mapping
CREATE TABLE example (
A text,
B text,
C text,
D text,
E text,
F text,
PRIMARY KEY ((A,B),C,D)
);
A|B|C| D|E|F
--+---+---+---+---+--a|b|c|d|e|f
a|b|c|g|h|i
a|b|j|k|l|m
a|n|o|p|q|r
s|t|u|v|w|x
OpenSource Connections
51. The CQL/Cassandra Mapping
CREATE TABLE example (
A text,
B text,
C text,
D text,
E text,
F text,
PRIMARY KEY ((A,B),C,D)
);
c:d:E
c:d:F
a:b
f
o:p:E
a:n
e
r
c:g:E
c:g:F
j:k:E
j:k:F
h
i
l
m
u:v:E
u:v:F
w
x
o:p:F
q
A|B|C| D|E|F
--+---+---+---+---+--a|b|c|d|e|f
a|b|c|g|h|i
a|b|j|k|l|m
a|n|o|p|q|r
s|t|u|v|w|x
s:t
OpenSource Connections
52. CQL for Sets, Lists, and Maps
• Collection Semantics
o Sets hold list of unique elements
o Lists hold ordered, possibly repeating elements
o Maps hold a list of key-value pairs
• Uses same old Cassandra data structure
OpenSource Connections
53. CQL for Sets, Lists, and Maps
• Collection Semantics
o Sets hold list of unique elements
o Lists hold ordered, possibly repeating elements
o Maps hold a list of key-value pairs
• Uses same old Cassandra data structure
• Declaring
CREATE TABLE mytable(
X text,
Y text,
myset set<text>,
mylist list<int>,
mymap map<text, text>,
PRIMARY KEY (X,Y)
);
OpenSource Connections
54. CQL for Sets, Lists, and Maps
• Collection Semantics
o Sets hold list of unique elements
o Lists hold ordered, possibly repeating elements
o Maps hold a list of key-value pairs
• Uses same old Cassandra data structure
• Declaring
CREATE TABLE mytable(
X text,
Y text,
myset set<text>,
mylist list<int>,
mymap map<text, text>,
PRIMARY KEY (X,Y)
);
Collection fields
can not be used
in primary keys
OpenSource Connections
55. CQL for Sets, Lists, and Maps
• Inserting
INSERT INTO mytable (row, myset)
VALUES (123, { ‘apple’, ‘banana’});
OpenSource Connections
56. CQL for Sets, Lists, and Maps
• Inserting
INSERT INTO mytable (row, myset)
VALUES (123, { ‘apple’, ‘banana’});
INSERT INTO mytable (row, mylist)
VALUES (123, [‘apple’,’banana’,’apple’]);
OpenSource Connections
57. CQL for Sets, Lists, and Maps
• Inserting
INSERT INTO mytable (row, myset)
VALUES (123, { ‘apple’, ‘banana’});
INSERT INTO mytable (row, mylist)
VALUES (123, [‘apple’,’banana’,’apple’]);
INSERT INTO mytable (row, mymap)
VALUES (123, {1:’apple’,2:’banana’})
OpenSource Connections
58. CQL for Sets, Lists, and Maps
• Updating
UPDATE mytable SET myset = myset + {‘apple’,‘banana’}
WHERE row = 123;
UPDATE mytable SET myset = myset - { ‘apple’ }
WHERE row = 123;
OpenSource Connections
59. CQL for Sets, Lists, and Maps
• Updating
UPDATE mytable SET myset = myset + {‘apple’,‘banana’}
WHERE row = 123;
UPDATE mytable SET myset = myset - { ‘apple’ }
WHERE row = 123;
UPDATE mytable SET mylist = mylist + [‘apple’,‘banana’]
WHERE row = 123;
UPDATE mytable SET mylist = [‘banana’] + mylist
WHERE row = 123;
OpenSource Connections
60. CQL for Sets, Lists, and Maps
• Updating
UPDATE mytable SET myset = myset + {‘apple’,‘banana’}
WHERE row = 123;
UPDATE mytable SET myset = myset - { ‘apple’ }
WHERE row = 123;
UPDATE mytable SET mylist = mylist + [‘apple’,‘banana’]
WHERE row = 123;
UPDATE mytable SET mylist = [‘banana’] + mylist
WHERE row = 123;
UPDATE mytable SET mymap[‘fruit’] = ‘apple’
WHERE row = 123
UPDATE mytable SET mymap = mymap + { ‘fruit’:‘apple’}
WHERE row = 123
OpenSource Connections
61. CQL for Sets, Lists, and Maps
SETS
CREATE TABLE mytable(
X text,
Y text,
myset set<int>,
PRIMARY KEY (X,Y)
);
OpenSource Connections
62. CQL for Sets, Lists, and Maps
SETS
CREATE TABLE mytable(
X text,
Y text,
myset set<int>,
PRIMARY KEY (X,Y)
);
X | Y | myset
---+---+-----------a | b | {1,2}
a | c | {3,4,5}
OpenSource Connections
63. CQL for Sets, Lists, and Maps
SETS
CREATE TABLE mytable(
X text,
Y text,
myset set<int>,
PRIMARY KEY (X,Y)
);
b:myset:1
b:myset:2
X | Y | myset
---+---+-----------a | b | {1,2}
a | c | {3,4,5}
c:myset:3
c:myset:4
c:myset:5
a
OpenSource Connections
64. CQL for Sets, Lists, and Maps
LISTS
CREATE TABLE mytable(
X text,
Y text,
mylist list<int>,
PRIMARY KEY (X,Y)
);
OpenSource Connections
65. CQL for Sets, Lists, and Maps
LISTS
CREATE TABLE mytable(
X text,
Y text,
mylist list<int>,
PRIMARY KEY (X,Y)
);
X | Y | mylist
---+---+-----------a | b | [1,2]
OpenSource Connections
66. CQL for Sets, Lists, and Maps
LISTS
CREATE TABLE mytable(
X text,
Y text,
mylist list<int>,
PRIMARY KEY (X,Y)
);
X | Y | mylist
---+---+-----------a | b | [1,2]
b:mylist:f7e5450039..8d
a
b:mylist:f7e5450139..8d
1
2
OpenSource Connections
67. CQL for Sets, Lists, and Maps
LISTS
CREATE TABLE mytable(
X text,
Y text,
mylist list<int>,
PRIMARY KEY (X,Y)
);
X | Y | mylist
---+---+-----------a | b | [1,2]
b:mylist:f7e5450039..8d
a
b:mylist:f7e5450139..8d
1
2
OpenSource Connections
68. CQL for Sets, Lists, and Maps
MAPS
CREATE TABLE mytable(
X text,
Y text,
mymap map<text,int>,
PRIMARY KEY (X,Y)
);
OpenSource Connections
69. CQL for Sets, Lists, and Maps
MAPS
CREATE TABLE mytable(
X text,
Y text,
mymap map<text,int>,
PRIMARY KEY (X,Y)
);
X | Y | mymap
---+---+-----------a | b | {m:1,n:2}
a | c |{n:3,p:4,q:5}
OpenSource Connections
70. CQL for Sets, Lists, and Maps
MAPS
X | Y | mymap
---+---+-----------a | b | {m:1,n:2}
a | c |{n:3,p:4,q:5}
CREATE TABLE mytable(
X text,
Y text,
mymap map<text,int>,
PRIMARY KEY (X,Y)
);
b:mymap:m
a
b:mymap:n
c:mymap:n
c:mymap:p
c:mymap:q
1
2
3
4
5
OpenSource Connections
71. Peek Behind the Scenes! Do it!
(in cqlsh)
CREATE KEYSPACE test WITH replication =
{'class': 'SimpleStrategy', 'replication_factor': 1};
USE test;
CREATE TABLE stuff ( a int, b int, myset set<int>,
mylist list<int>, mymap map<int,int>, PRIMARY KEY (a,b));
UPDATE stuff SET myset = {1,2}, mylist = [3,4,5], mymap = {6:7,8:9} WHERE a = 0
AND b = 1;
SELECT * FROM stuff;
(in cassandra-cli)
use test;
list stuff ;
(in cqlsh)
SELECT key_aliases,column_aliases from system.schema_columnfamilies WHERE
keyspace_name = 'test' AND columnfamily_name = 'stuff';
OpenSource Connections
72. Putting it All Together
…you already know
• CQL is a reintroduction of schema
• CQL creates a common data modeling language
• CQL is a best-practices Cassandra interface
.
OpenSource Connections
73. Putting it All Together
…you already know
• CQL is a reintroduction of schema
• CQL creates a common data modeling language
• CQL is a best-practices Cassandra interface
…now you know
• CQL let’s you take advantage of the C* Data structure
.
OpenSource Connections
74. Putting it All Together
…you already know
• CQL is a reintroduction of schema
• CQL creates a common data modeling language
• CQL is a best-practices Cassandra interface
…now you know
• CQL let’s you take advantage of the C* Data structure
…but also
• CQL protocol is binary and therefore interoperable with
any language
• CQL is asynchronous and fast (Thrift transport layer is
synchronous)
• CQL allows the possibility for prepared statements
OpenSource Connections
75. Thanks!
Follow me on Twitter @JnBrymn
Check out the OpenSource Connection Blog
http://www.opensourceconnections.com/blog/
OpenSource Connections
Hinweis der Redaktion
No need to bother with composite column names or row keys.Grouping fields into SQL-like rows.Easy-to-use collections.
No need to bother with composite column names or row keys.Grouping fields into SQL-like rows.Easy-to-use collections.
No need to bother with composite column names or row keys.Grouping fields into SQL-like rows.Easy-to-use collections.