diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index 0c60077e1f..2c0827a440 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -326,13 +326,25 @@ pgbench options d + + + + + Create extra indexes on the standard tables for referenced FK columns. + (This option adds the i step to the initialization + step sequence, if it is not already present.) + + + + Create foreign key constraints between the standard tables. (This option adds the f step to the initialization - step sequence, if it is not already present.) + step sequence, if it is not already present.) Also implies + . @@ -410,7 +422,7 @@ pgbench options d Add the specified built-in script to the list of scripts to be executed. - Available built-in scripts are: tpcb-like, + Available built-in scripts are: tpcb-like, insert-only, simple-update and select-only. Unambiguous prefixes of built-in names are accepted. With the special name list, show the list of built-in scripts @@ -489,6 +501,16 @@ pgbench options d + + + + + Run built-in insert-only script. + Shorthand for . + + + + threads threads @@ -986,6 +1008,11 @@ pgbench options d If you select the select-only built-in (also ), only the SELECT is issued. + + + If you select the insert-only built-in, + only the INSERT is issued. + diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 4aeccd93af..cb30082c58 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -85,6 +85,12 @@ #define MM2_MUL_TIMES_8 UINT64CONST(0x35253c9ade8f4ca8) #define MM2_ROT 47 +/* Filler strings of indicated lenghts */ +#define FILLER_ACCOUNTS_PADDING "123456789012345678901234567890123456789012345678901234567890123456789012345678901234" +#define FILLER_BRANCHES_PADDING "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678" +#define FILLER_HISTORY_PADDING "1234567890123456789012" +#define FILLER_TELLERS_PADDING "123456789012345678901234567890123456789012345678901234567890123456789012345678901234" + /* * Multi-platform socket set implementations */ @@ -616,7 +622,7 @@ static const BuiltinScript builtin_script[] = "SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n" "UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;\n" "UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n" - "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n" + "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime, filler) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP, " FILLER_HISTORY_PADDING ");\n" "END;\n" }, { @@ -629,7 +635,7 @@ static const BuiltinScript builtin_script[] = "BEGIN;\n" "UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n" "SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n" - "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n" + "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime, filler) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP, " FILLER_HISTORY_PADDING ");\n" "END;\n" }, { @@ -637,6 +643,15 @@ static const BuiltinScript builtin_script[] = "", "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n" "SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n" + }, + { + "insert-only", + "", + "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n" + "\\set bid random(1, " CppAsString2(nbranches) " * :scale)\n" + "\\set tid random(1, " CppAsString2(ntellers) " * :scale)\n" + "\\set delta random(-5000, 5000)\n" + "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime, filler) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP, " FILLER_HISTORY_PADDING ");\n" } }; @@ -703,6 +718,7 @@ usage(void) " -n, --no-vacuum do not run VACUUM during initialization\n" " -q, --quiet quiet logging (one message each 5 seconds)\n" " -s, --scale=NUM scaling factor\n" + " --extra-indexes create additional indexes on the tables\n" " --foreign-keys create foreign key constraints between tables\n" " --index-tablespace=TABLESPACE\n" " create indexes in the specified tablespace\n" @@ -719,6 +735,8 @@ usage(void) " (same as \"-b simple-update\")\n" " -S, --select-only perform SELECT-only transactions\n" " (same as \"-b select-only\")\n" + " --insert-only perform INSERT-only transactions\n" + " (same as \"-b insert-only\")\n" "\nBenchmarking options:\n" " -c, --client=NUM number of concurrent database clients (default: 1)\n" " -C, --connect establish new connection for each transaction\n" @@ -4009,14 +4027,12 @@ initCreateTables(PGconn *con) { /* * Note: TPC-B requires at least 100 bytes per row, and the "filler" - * fields in these table declarations were intended to comply with that. - * The pgbench_accounts table complies with that because the "filler" - * column is set to blank-padded empty string. But for all other tables - * the columns default to NULL and so don't actually take any space. We - * could fix that by giving them non-null default values. However, that - * would completely break comparability of pgbench results with prior - * versions. Since pgbench has never pretended to be fully TPC-B compliant - * anyway, we stick with the historical behavior. + * fields in these table declarations comply with that. This does change + * how "pgbench" has traditionally handled this, which in versions prior + * to 15 used NULL values for this field for every table but the accounts + * table. It was determined that having this timing data be comparable to + * other benchmarking tools was more important than compatibility with + * previous runs of pgbench. */ struct ddlinfo { @@ -4146,18 +4162,16 @@ initGenerateDataClientSide(PGconn *con) */ for (i = 0; i < nbranches * scale; i++) { - /* "filler" column defaults to NULL */ printfPQExpBuffer(&sql, - "insert into pgbench_branches(bid,bbalance) values(%d,0)", + "insert into pgbench_branches(bid,bbalance,filler) values(%d,0,'" FILLER_BRANCHES_PADDING "')", i + 1); executeStatement(con, sql.data); } for (i = 0; i < ntellers * scale; i++) { - /* "filler" column defaults to NULL */ printfPQExpBuffer(&sql, - "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)", + "insert into pgbench_tellers(tid,bid,tbalance,filler) values (%d,%d,0,'" FILLER_TELLERS_PADDING "')", i + 1, i / ntellers + 1); executeStatement(con, sql.data); } @@ -4181,7 +4195,7 @@ initGenerateDataClientSide(PGconn *con) /* "filler" column defaults to blank padded empty string */ printfPQExpBuffer(&sql, - INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n", + INT64_FORMAT "\t" INT64_FORMAT "\t%d\t" FILLER_ACCOUNTS_PADDING "\n", j, k / naccounts + 1, 0); if (PQputline(con, sql.data)) { @@ -4248,8 +4262,8 @@ initGenerateDataClientSide(PGconn *con) * Fill the standard tables with some data generated on the server * * As already the case with the client-side data generation, the filler - * column defaults to NULL in pgbench_branches and pgbench_tellers, - * and is a blank-padded string in pgbench_accounts. + * columns default to blank-padded strings, so bring the record size up to + * 100. */ static void initGenerateDataServerSide(PGconn *con) @@ -4270,20 +4284,20 @@ initGenerateDataServerSide(PGconn *con) initPQExpBuffer(&sql); printfPQExpBuffer(&sql, - "insert into pgbench_branches(bid,bbalance) " - "select bid, 0 " + "insert into pgbench_branches(bid,bbalance,filler) " + "select bid, 0, '" FILLER_BRANCHES_PADDING "' " "from generate_series(1, %d) as bid", nbranches * scale); executeStatement(con, sql.data); printfPQExpBuffer(&sql, - "insert into pgbench_tellers(tid,bid,tbalance) " - "select tid, (tid - 1) / %d + 1, 0 " + "insert into pgbench_tellers(tid,bid,tbalance,filler) " + "select tid, (tid - 1) / %d + 1, 0, '" FILLER_TELLERS_PADDING "' " "from generate_series(1, %d) as tid", ntellers, ntellers * scale); executeStatement(con, sql.data); printfPQExpBuffer(&sql, "insert into pgbench_accounts(aid,bid,abalance,filler) " - "select aid, (aid - 1) / %d + 1, 0, '' " + "select aid, (aid - 1) / %d + 1, 0, '" FILLER_ACCOUNTS_PADDING "' " "from generate_series(1, " INT64_FORMAT ") as aid", naccounts, (int64) naccounts * scale); executeStatement(con, sql.data); @@ -4366,6 +4380,28 @@ initCreateFKeys(PGconn *con) } } +/* + * Create extra indexes on the standard tables + */ +static void +initCreateExtraIndexes(PGconn *con) +{ + static const char *const DDLKEYs[] = { + "create index pgbench_tellers_bid_idx on pgbench_tellers (bid)", + "create index pgbench_accounts_bid_idx on pgbench_accounts (bid)", + "create index pgbench_history_aid_idx on pgbench_history (aid)", + "create index pgbench_history_bid_idx on pgbench_history (bid)", + "create index pgbench_history_tid_idx on pgbench_history (tid)" + }; + int i; + + fprintf(stderr, "creating extra indexes...\n"); + for (i = 0; i < lengthof(DDLKEYs); i++) + { + executeStatement(con, DDLKEYs[i]); + } +} + /* * Validate an initialization-steps string * @@ -4448,6 +4484,10 @@ runInitSteps(const char *initialize_steps) op = "foreign keys"; initCreateFKeys(con); break; + case 'i': + op = "extra indexes"; + initCreateExtraIndexes(con); + break; case ' ': break; /* ignore */ default: @@ -5769,6 +5809,8 @@ main(int argc, char **argv) {"show-script", required_argument, NULL, 10}, {"partitions", required_argument, NULL, 11}, {"partition-method", required_argument, NULL, 12}, + {"insert-only", no_argument, NULL, 13}, + {"extra-indexes", no_argument, NULL, 14}, {NULL, 0, NULL, 0} }; @@ -5776,6 +5818,7 @@ main(int argc, char **argv) bool is_init_mode = false; /* initialize mode? */ char *initialize_steps = NULL; bool foreign_keys = false; + bool extra_indexes = false; bool is_no_vacuum = false; bool do_vacuum_accounts = false; /* vacuum accounts table? */ int optindex; @@ -6137,6 +6180,15 @@ main(int argc, char **argv) exit(1); } break; + case 13: /* insert-only */ + process_builtin(findBuiltin("insert-only"), 1); + benchmarking_option_set = true; + internal_script_used = true; + break; + case 14: /* indexes */ + initialization_option_set = true; + extra_indexes = true; + break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); @@ -6252,6 +6304,19 @@ main(int argc, char **argv) } } + /* foreign_keys always implies extra_indexes */ + if (extra_indexes || foreign_keys) + { + /* Add 'i' to end of initialize_steps, if not already there */ + if (strchr(initialize_steps, 'i') == NULL) + { + initialize_steps = (char *) + pg_realloc(initialize_steps, + strlen(initialize_steps) + 2); + strcat(initialize_steps, "i"); + } + } + runInitSteps(initialize_steps); exit(0); } diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index c2a35a488a..e8cd07e9c9 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -102,15 +102,13 @@ all: all-lib check-libpq-refs include $(top_srcdir)/src/Makefile.shlib backend_src = $(top_srcdir)/src/backend -# Check for functions that libpq must not call, currently just exit(). -# (Ideally we'd reject abort() too, but there are various scenarios where -# build toolchains silently insert abort() calls, e.g. when profiling.) -# If nm doesn't exist or doesn't work on shlibs, this test will do nothing, -# which is fine. The exclusion of __cxa_atexit is necessary on OpenBSD, -# which seems to insert references to that even in pure C code. +# Check for functions that libpq must not call, currently abort() and exit(). +# If nm doesn't exist or doesn't work on shlibs, this test will silently +# do nothing, which is fine. The exclusion of _eprintf.o is to prevent +# complaining about infrastructure on ancient macOS releases. .PHONY: check-libpq-refs check-libpq-refs: $(shlib) - ! nm -A -g -u $< 2>/dev/null | grep -v __cxa_atexit | grep exit + ! nm -A -g -u $< 2>/dev/null | grep -v '_eprintf\.o:' | grep -e abort -e exit # Make dependencies on pg_config_paths.h visible in all builds. fe-connect.o: fe-connect.c $(top_builddir)/src/port/pg_config_paths.h