Add WITHOUT ROWID to SQLite benchmark.

The SQLite-specific schema feature is documented at
https://www.sqlite.org/withoutrowid.html and
https://www.sqlite.org/rowidtable.html.

By default, SQLite stores each table in a B-tree keyed by an integer,
called the ROWID. Any index, including the PRIMARY KEY index, is a
separate B-tree mapping index keys to ROWIDs. Tables without ROWIDs are
stored in a B-tree keyed by the primary key. Additional indexes (the
PRIMARY KEY index is implicitly built into the table) are stored as
B-trees mapping index keys to row primary keys.

This CL introduces a boolean --use-rowids flag to db_bench_sqlite. When
the flag is false (default), the schema of the test table includes
WITHOUT ROWID. The test table uses a primary key, so adding WITHOUT
ROWID to the schema reduces the number of B-trees used by the benchmark
from 2 to 1. This brings SQLite's disk usage closer to LevelDB.

When WITHOUT ROWID is used, SQLite fares better (than today) on
benchmarks with small (16-byte) keys, and worse on benchmarks with large
(100kb) keys.

Baseline results:
fillseq      :      21.310 micros/op;    5.2 MB/s
fillseqsync  :     146.377 micros/op;    0.8 MB/s (10000 ops)
fillseqbatch :       2.065 micros/op;   53.6 MB/s
fillrandom   :      34.767 micros/op;    3.2 MB/s
fillrandsync :     159.943 micros/op;    0.7 MB/s (10000 ops)
fillrandbatch :      15.055 micros/op;    7.3 MB/s
overwrite    :      43.660 micros/op;    2.5 MB/s
overwritebatch :      27.691 micros/op;    4.0 MB/s
readrandom   :      12.725 micros/op;
readseq      :       2.602 micros/op;   36.7 MB/s
fillrand100K :     606.333 micros/op;  157.3 MB/s (1000 ops)
fillseq100K  :     657.457 micros/op;  145.1 MB/s (1000 ops)
readseq      :      46.523 micros/op; 2049.9 MB/s
readrand100K :      54.943 micros/op;

Results after this CL:
fillseq      :      16.231 micros/op;    6.8 MB/s
fillseqsync  :     147.460 micros/op;    0.8 MB/s (10000 ops)
fillseqbatch :       2.294 micros/op;   48.2 MB/s
fillrandom   :      27.871 micros/op;    4.0 MB/s
fillrandsync :     141.979 micros/op;    0.8 MB/s (10000 ops)
fillrandbatch :      16.087 micros/op;    6.9 MB/s
overwrite    :      26.829 micros/op;    4.1 MB/s
overwritebatch :      19.014 micros/op;    5.8 MB/s
readrandom   :      11.657 micros/op;
readseq      :       0.155 micros/op;  615.0 MB/s
fillrand100K :     816.812 micros/op;  116.8 MB/s (1000 ops)
fillseq100K  :     754.689 micros/op;  126.4 MB/s (1000 ops)
readseq      :      47.112 micros/op; 2024.3 MB/s
readrand100K :     287.679 micros/op;

Results after this CL, with --use-rowids=1
fillseq      :      20.655 micros/op;    5.4 MB/s
fillseqsync  :     146.408 micros/op;    0.8 MB/s (10000 ops)
fillseqbatch :       2.045 micros/op;   54.1 MB/s
fillrandom   :      34.080 micros/op;    3.2 MB/s
fillrandsync :     154.582 micros/op;    0.7 MB/s (10000 ops)
fillrandbatch :      14.404 micros/op;    7.7 MB/s
overwrite    :      42.928 micros/op;    2.6 MB/s
overwritebatch :      27.829 micros/op;    4.0 MB/s
readrandom   :      12.835 micros/op;
readseq      :       2.483 micros/op;   38.4 MB/s
fillrand100K :     603.265 micros/op;  158.1 MB/s (1000 ops)
fillseq100K  :     662.473 micros/op;  144.0 MB/s (1000 ops)
readseq      :      45.478 micros/op; 2097.0 MB/s
readrand100K :      54.439 micros/op;
PiperOrigin-RevId: 283407101
This commit is contained in:
Victor Costan 2019-12-02 13:37:34 -08:00 committed by Victor Costan
parent c0d43142ff
commit 58a89bbcb2

View File

@ -69,6 +69,9 @@ static int FLAGS_num_pages = 4096;
// benchmark will fail. // benchmark will fail.
static bool FLAGS_use_existing_db = false; static bool FLAGS_use_existing_db = false;
// If true, the SQLite table has ROWIDs.
static bool FLAGS_use_rowids = false;
// If true, we allow batch writes to occur // If true, we allow batch writes to occur
static bool FLAGS_transaction = true; static bool FLAGS_transaction = true;
@ -462,6 +465,7 @@ class Benchmark {
std::string locking_stmt = "PRAGMA locking_mode = EXCLUSIVE"; std::string locking_stmt = "PRAGMA locking_mode = EXCLUSIVE";
std::string create_stmt = std::string create_stmt =
"CREATE TABLE test (key blob, value blob, PRIMARY KEY(key))"; "CREATE TABLE test (key blob, value blob, PRIMARY KEY(key))";
if (!FLAGS_use_rowids) create_stmt += " WITHOUT ROWID";
std::string stmt_array[] = {locking_stmt, create_stmt}; std::string stmt_array[] = {locking_stmt, create_stmt};
int stmt_array_length = sizeof(stmt_array) / sizeof(std::string); int stmt_array_length = sizeof(stmt_array) / sizeof(std::string);
for (int i = 0; i < stmt_array_length; i++) { for (int i = 0; i < stmt_array_length; i++) {
@ -678,6 +682,9 @@ int main(int argc, char** argv) {
} else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 && } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) { (n == 0 || n == 1)) {
FLAGS_use_existing_db = n; FLAGS_use_existing_db = n;
} else if (sscanf(argv[i], "--use_rowids=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_use_rowids = n;
} else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) {
FLAGS_num = n; FLAGS_num = n;
} else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) {