diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml
index 03e1212d50..8148364125 100644
--- a/doc/src/sgml/ref/pgbench.sgml
+++ b/doc/src/sgml/ref/pgbench.sgml
@@ -1014,6 +1014,14 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
        <entry>an integer between <literal>1</> and <literal>10</></>
       </row>
       <row>
+        <entry><literal><function>random_zipfian(<replaceable>lb</>, <replaceable>ub</>, <replaceable>parameter</>)</></></>
+        <entry>integer</>
+        <entry> Zipfian-distributed random integer in <literal>[lb, ub]</>,
+              see below</>
+        <entry><literal>random_zipfian(1, 10, 0.5)</></>
+        <entry>an integer between <literal>1</> and <literal>10</></>
+      </row>
+      <row>
        <entry><literal><function>sqrt(<replaceable>x</>)</></></>
        <entry>double</>
        <entry>square root</>
@@ -1094,6 +1102,25 @@ f(x) = PHI(2.0 * parameter * (x - mu) / (max - min + 1)) /
       of the Box-Muller transform.
      </para>
     </listitem>
+    <listitem>
+        <para>
+          <literal>random_zipfian</> generates only approximate distribution and degree of proximity depends on <replaceable>parameter</>.
+          For good accuracy it's better to choose <replaceable>parameter</> in range (0, 1). 
+        </para>
+        <para>
+          <replaceable>parameter</> 
+          defines how skewed the distribution. A physical sense of this parameter
+          is following: probability of <literal>i</>th element <literal>f(i) = (1 / (i ^ parameter)) /
+          (H(N, parameter))</> where <literal>N</> is number of elements in range and <literal>H(N, parameter)</>
+          is <literal>N</>th generalized harmonic number. 
+        </para>
+        <para>
+          Intuitively, the larger the <replaceable>parameter</>, the more
+          frequently value values to the beginning of the interval are drawn. 
+          The closer to 0 <replaceable>parameter</> is, 
+          the flatter (more uniform) the access distribution.
+        </para>
+    </listitem>
    </itemizedlist>
 
   <para>
diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y
index b3a2d9bfd3..25d5ad48e5 100644
--- a/src/bin/pgbench/exprparse.y
+++ b/src/bin/pgbench/exprparse.y
@@ -191,6 +191,9 @@ static const struct
 	{
 		"random_exponential", 3, PGBENCH_RANDOM_EXPONENTIAL
 	},
+	{
+		"random_zipfian", 3, PGBENCH_RANDOM_ZIPFIAN
+	},
 	/* keep as last array element */
 	{
 		NULL, 0, 0
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index ae78c7b1d4..f902fdd64e 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -93,6 +93,8 @@ static int	pthread_join(pthread_t th, void **thread_return);
 #define LOG_STEP_SECONDS	5	/* seconds between log messages */
 #define DEFAULT_NXACTS	10		/* default nxacts */
 
+#define ZIPF_CACHE_SIZE	15		/* cache cells number */
+
 #define MIN_GAUSSIAN_PARAM		2.0 /* minimum parameter for gauss */
 
 int			nxacts = 0;			/* number of transactions per client */
@@ -334,6 +336,36 @@ typedef struct
 } CState;
 
 /*
+ * Cache cell for zipfian_random call
+ */
+typedef struct
+{
+	/* cell keys */
+	double		s;				/* s - parameter of zipfan_random function */
+	int64		n;				/* number of elements in range (max - min + 1) */
+
+	double		harmonicn;		/* zipfGeneralizedHarmonic(n, s) */
+	double		alpha;
+	double		beta;
+	double		eta;
+
+	uint64		last_touch_time;	/* time when cell was used last time */
+} ZipfCell;
+
+/*
+ * Zipf cache for zeta values
+ */
+typedef struct
+{
+	uint64		current_time;	/* counter for LRU cache replacement algorithm */
+
+	int			cells_inited;	/* number of filled cells */
+	ZipfCell	cells[ZIPF_CACHE_SIZE];
+} ZipfCache;
+
+bool		zipfCacheOverflowMessagePrinted = false;
+
+/*
  * Thread state
  */
 typedef struct
@@ -345,6 +377,8 @@ typedef struct
 	unsigned short random_state[3]; /* separate randomness for each thread */
 	int64		throttle_trigger;	/* previous/next throttling (us) */
 	FILE	   *logfile;		/* where to log, or NULL */
+	ZipfCache	zipf_cache;		/* for thread-safe  zipfian random number
+								 * generation */
 
 	/* per thread collected stats */
 	instr_time	start_time;		/* thread start time */
@@ -737,6 +771,137 @@ getPoissonRand(TState *thread, int64 center)
 	return (int64) (-log(uniform) * ((double) center) + 0.5);
 }
 
+/* helper function for getZipfianRand */
+static double
+zipfGeneralizedHarmonic(int64 n, double s)
+{
+	int			i;
+	double		ans = 0.0;
+
+	for (i = n; i > 1; i--)
+		ans += pow(i, -s);
+	return ans + 1.;
+}
+
+/* helper function for getZipfianRand. Computes random variable in range 1..n */
+static int64
+zipfn(double uniform_random, ZipfCell * zipf, int64 n, double s)
+{
+	double		uz = uniform_random * zipf->harmonicn;
+
+	if (uz < 1.)
+		return 1;
+	if (uz < 1. + zipf->beta)
+		return 2;
+	return 1 + (int64) (n * pow(zipf->eta * uniform_random - zipf->eta + 1., zipf->alpha));
+}
+
+/* set harmonicn and other parameters to cache cell */
+static void
+zipfSetCacheCell(ZipfCell * cell, int64 n, double s)
+{
+	double		harmonic2;
+
+	cell->n = n;
+	cell->s = s;
+
+	harmonic2 = zipfGeneralizedHarmonic(2, s);
+	cell->harmonicn = zipfGeneralizedHarmonic(n, s);
+
+	cell->alpha = 1.0 / (1.0 - s);
+	cell->beta = pow(0.5, s);
+	cell->eta = (1.0 - pow(2.0 / n, 1.0 - s)) / (1.0 - harmonic2 / cell->harmonicn);
+}
+
+/*
+ * search for cache cell with keys (n, s)
+ * and create new cell if it is not exist
+ */
+static ZipfCell *
+zipfFindOrCreateCacheCell(ZipfCache * cache, int64 n, double s)
+{
+	int			i,
+				least_recently_used_i = 0;
+	ZipfCell   *cell;
+
+	/* search cached cell for given parameters */
+	for (i = 0; i < cache->cells_inited; i++)
+	{
+		cell = &cache->cells[i];
+		if (cell->n == n && cell->s == s)
+			return &cache->cells[i];
+
+		if (cell->last_touch_time < cache->cells[least_recently_used_i].last_touch_time)
+			least_recently_used_i = i;
+	}
+
+	/* create new one if it is not exist */
+	if (cache->cells_inited != ZIPF_CACHE_SIZE)
+		i = cache->cells_inited++;
+	else
+	{
+		/* replace LRU cell if cache is full */
+		i = least_recently_used_i;
+		if (!zipfCacheOverflowMessagePrinted)
+		{
+			/*
+			 * flag can be accessed in several threads simultaneously and
+			 * message can be printed more than one time
+			 */
+			zipfCacheOverflowMessagePrinted = true;
+			fprintf(stderr, "zipfian cache array overflowed\n");
+		}
+	}
+
+	zipfSetCacheCell(&cache->cells[i], n, s);
+
+	return &cache->cells[i];
+}
+
+static int64
+computeIterativeZipfian(unsigned short random_state[3], int64 n, double s)
+{
+	/* computing zipfian using rejection method */
+	double		b = pow(2.0, s - 1.0);
+	double		x,
+				t,
+				u,
+				v;
+
+	while (1)
+	{
+		/* random variates */
+		u = pg_erand48(random_state);
+		v = pg_erand48(random_state);
+
+		x = floor(pow(u, -1.0 / (s - 1.0)));
+
+		t = pow(1.0 + 1.0 / x, s - 1.0);
+		/* reject if too large or out of bound */
+		if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
+			break;
+	}
+	return (int64) x;
+}
+
+/* random number generator: zipfian distribution from min to max inclusive */
+static int64
+getZipfianRand(TState *thread, int64 min, int64 max, double s)
+{
+	int64		n = max - min + 1;
+
+	if (s > 1)
+		/* it is better to use iterative way to compute when s > 1 */
+		return min + computeIterativeZipfian(thread->random_state, n, s) - 1;
+
+	ZipfCell   *cell = zipfFindOrCreateCacheCell(&thread->zipf_cache, n, s);
+
+	cell->last_touch_time = thread->zipf_cache.current_time++;
+	double		uniform = pg_erand48(thread->random_state);
+
+	return min + zipfn(uniform, cell, n, s) - 1;
+}
+
 /*
  * Initialize the given SimpleStats struct to all zeroes
  */
@@ -1567,6 +1732,7 @@ evalFunc(TState *thread, CState *st,
 		case PGBENCH_RANDOM:
 		case PGBENCH_RANDOM_EXPONENTIAL:
 		case PGBENCH_RANDOM_GAUSSIAN:
+		case PGBENCH_RANDOM_ZIPFIAN:
 			{
 				int64		imin,
 							imax;
@@ -1617,6 +1783,18 @@ evalFunc(TState *thread, CState *st,
 						setIntValue(retval,
 									getGaussianRand(thread, imin, imax, param));
 					}
+					else if (func == PGBENCH_RANDOM_ZIPFIAN)
+					{
+						if (param <= 0.0 || param == 1.0)
+						{
+							fprintf(stderr,
+									"zipfian parameter must be greater than 0 and cannot be 1"
+									" (got %f)\n", param);
+							return false;
+						}
+						setIntValue(retval,
+									getZipfianRand(thread, imin, imax, param));
+					}
 					else		/* exponential */
 					{
 						if (param <= 0.0)
@@ -4273,6 +4451,8 @@ main(int argc, char **argv)
 		thread->random_state[2] = random();
 		thread->logfile = NULL; /* filled in later */
 		thread->latency_late = 0;
+		thread->zipf_cache.cells_inited = 0;
+		thread->zipf_cache.current_time = 0;
 		initStats(&thread->stats, 0);
 
 		nclients_dealt += thread->nstate;
diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h
index abc13e9463..1a29f1260c 100644
--- a/src/bin/pgbench/pgbench.h
+++ b/src/bin/pgbench/pgbench.h
@@ -75,7 +75,8 @@ typedef enum PgBenchFunction
 	PGBENCH_SQRT,
 	PGBENCH_RANDOM,
 	PGBENCH_RANDOM_GAUSSIAN,
-	PGBENCH_RANDOM_EXPONENTIAL
+	PGBENCH_RANDOM_EXPONENTIAL,
+	PGBENCH_RANDOM_ZIPFIAN
 } PgBenchFunction;
 
 typedef struct PgBenchExpr PgBenchExpr;
