Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eMjNq-0000go-4m for pgsql-bugs@arkaria.postgresql.org; Wed, 06 Dec 2017 23:45:46 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eMjNp-0005uV-Ny for pgsql-bugs@arkaria.postgresql.org; Wed, 06 Dec 2017 23:45:45 +0000 Received: from makus.postgresql.org ([2001:4800:1501:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1eMjNp-0005uL-FN for pgsql-bugs@lists.postgresql.org; Wed, 06 Dec 2017 23:45:45 +0000 Received: from mail-wm0-x22d.google.com ([2a00:1450:400c:c09::22d]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1eMjNm-00039s-6w for pgsql-bugs@postgresql.org; Wed, 06 Dec 2017 23:45:44 +0000 Received: by mail-wm0-x22d.google.com with SMTP id g75so10219437wme.0 for ; Wed, 06 Dec 2017 15:45:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language; bh=VQsYN1pFF1C2+meWrKswUIq7WWh3VbPqovZhm5+ghX0=; b=a4jlNSlTvlQWYhtcWgIOFY2tGT6mxRiAgwg+nCS71Y/PV7vA+qIznuofFQdeHTMihE TmtSbU1a5zjGqTxgosEaWAuD06evN8Xh2PhiqVt4t56BlM34cfvsyb42X+7TotgqynM3 VFL/xNhgLt8NF5ANfs57Lj10JVbNbPCTH4uqQmTdhsIBV8bMgvopnaojlcNOyh4ZsOPk DZLAwPOOSKpZgSRWWqpzbMiVa+sCwE8LKgdAII1wX7cAFvkRO3Rw5TS42cbHrXDBF8N0 0QbUWadtnSmjkd9v6+CvIk/qB8IUv4KeowtvZg2mDOWEtNA7bSTcOSkahMpqLahu0xpe NWnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language; bh=VQsYN1pFF1C2+meWrKswUIq7WWh3VbPqovZhm5+ghX0=; b=KN922wGhgMr1moyl1fXdtUndc4za28tfJbYSfrf7l/Kg8L+TO5HSCsERgNfpd3pKlv TLyfku9wTm4Sl8nrkWNXHyQf/DE9YMCW1cLvNyOl6+iD05rQz1ntxJup0ezCSMaG05jd t+04NQVIDuMc8a9AkA2ZKHYzs8L4/vNHETjoAeGEP3xb6G8d7Ai/WSZ/SLidO7afm0Gu 01a3efdGy7eAh4eILxkfhdaovCPkGtRGC3rKvEi4DZVknu7ZPejSvy3O6Lh7V05gV/kt YCepy+OExIXUzUCXP+A7O53A8+6yVadqudabY79JY1PvoM6wbXfrJ3y8BfZk44Ub3/0R nh0A== X-Gm-Message-State: AJaThX6p0Ow44U+oYDc+aHxK1Jct7gfQGoZOCXAbckd5t929YQ3r+MGB TRU6NNXLJLTI4RIjta9762JUgTgFP/ntxFrrFtz3z7azpaM7+WPhpdf7hl/nXQ8boZWeS9QC2/s WyfiEGTBuK5Y/W8BHkscO/yqa8skhp6/lEEk8vxWrAur1RItPlmTkreZ5lXDeUluwhyGRL99ykj W7Vr1N X-Google-Smtp-Source: AGs4zMbXBwTAZR4qQicd5E0MxZBAP+jfVSOGEnHJLEFpjwhOBQUUUeO9EFOB5NOUuwD8TT8kUruGsQ== X-Received: by 10.28.13.212 with SMTP id 203mr12742091wmn.141.1512603939332; Wed, 06 Dec 2017 15:45:39 -0800 (PST) Received: from [10.137.2.19] (ip-78-102-97-226.net.upcbroadband.cz. [78.102.97.226]) by smtp.gmail.com with ESMTPSA id d9sm3956199wrf.45.2017.12.06.15.45.37 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Dec 2017 15:45:38 -0800 (PST) Subject: Re: BUG #14932: SELECT DISTINCT val FROM table gets stuck in an infinite loop To: Tom Lane , Andres Freund Cc: "Todd A. Cook" , Thomas Munro , PostgreSQL Bugs References: <2a76784c-06cb-46ec-35be-9895d144b839@2ndquadrant.com> <263b03b1-3e1c-49ca-165a-8ac6751419c4@2ndquadrant.com> <20171206193545.3imvbfwjgrmuho3s@alap3.anarazel.de> <790BC80E-D8E5-499B-A1E3-8EE0752B53ED@anarazel.de> <06523583-b9c5-1424-ef0a-1fc8063e9ed7@2ndquadrant.com> <20171206204616.wcect35fuj5gjde2@alap3.anarazel.de> <67e5af9b-f509-7b9e-f7a1-e01112f6c18d@2ndquadrant.com> <20171206211225.zcp2crfr3bssn3xr@alap3.anarazel.de> <21d507d9-9024-33a8-37c8-b472b3dce7df@blackducksoftware.com> <20171206214003.lvz3q5coaewxr7vp@alap3.anarazel.de> <16912.1512600919@sss.pgh.pa.us> From: Tomas Vondra Message-ID: <0e91ba4e-5afc-220e-b1f7-56a838aee845@2ndquadrant.com> Date: Thu, 7 Dec 2017 00:45:34 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.3.0 MIME-Version: 1.0 In-Reply-To: <16912.1512600919@sss.pgh.pa.us> Content-Type: multipart/mixed; boundary="------------3F757AA8719B60C565E1099D" Content-Language: en-US List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk This is a multi-part message in MIME format. --------------3F757AA8719B60C565E1099D Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit On 12/06/2017 11:55 PM, Tom Lane wrote: > Andres Freund writes: >> On 2017-12-06 16:38:18 -0500, Todd A. Cook wrote: >>> I found this problem when I dropped 10.1 into a test environment to see >>> what would happen. There was no deliberate attempt to break anything. > >> Read Thomas' message at: http://archives.postgresql.org/message-id/263b03b1-3e1c-49ca-165a-8ac6751419c4%402ndquadrant.com > > I'm confused by Tomas' claim that > >>> (essentially hashint8 only ever produces 60% of >>> values from [0,1000000], which likely increases collision rate). > > This is directly contradicted by the simple experiments I've done, eg > > regression=# select count(distinct hashint8(v)) from generate_series(0,1000000::int8) v; > count > -------- > 999879 > (1 row) > > regression=# select count(distinct hashint8(v) & (1024*1024-1)) from generate_series(0,1000000::int8) v; > count > -------- > 644157 > (1 row) > > regression=# select count(distinct hashint8(v) & (1024*1024-1)) from generate_series(0,10000000::int8) v; > count > --------- > 1048514 > (1 row) > > It's certainly not perfect, but I'm not observing any major failure to > span the output space. > That is not the claim I was making, though. When generating data sets I've been considering only values where hashint8(v) is between 0 and 1000000 *without* the masking. Otherwise growing the hash table would break the "chain" of values in the hash table, which would resolve the issue with SH_GROW_MAX_MOVE. So you'd have to do something like this: select count(distinct hashint8(v)) from generate_series(0,1000000::int8) v where hashint8(v) between 0 and 1024*1024; but to get some numbers you'd have to also increase the value passed to generate_series (because it'll filter most of the values). Which is why I generated the data by an ugly C program, similar to the attached one. It keeps a small bitmap for generated hashes in the [0,1M] range, and prints the number of bits set after every 1e9 values processed. What I do see is this: i=1000000000 nset=217666 i=2000000000 nset=389526 i=3000000000 nset=525135 i=4000000000 nset=632305 i=5000000000 nset=659574 i=6000000000 nset=659574 i=7000000000 nset=659574 i=8000000000 nset=659574 i=9000000000 nset=659574 ... So somewhere between 4e9 and 5e9 we generate 659574 hashes in the range, and then never increase it further. I don't know if this an issue in practice, but it seems that for large hash tables (on bigint), growing the hash table may not be that great improvement because we're not really doubling the number of slots we can hit directly. We'll probably find an empty slot nearby, though. It was just an observation - I only noticed that because I tried to construct the adversarial data set on bigint, and couldn't make it work no matter what. regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services --------------3F757AA8719B60C565E1099D Content-Type: text/x-csrc; name="duplicities-bigint.c" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="duplicities-bigint.c" #include #include #include #include #include #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) #define mix(a,b,c) \ { \ a -= c; a ^= rot(c, 4); c += b; \ b -= a; b ^= rot(a, 6); a += c; \ c -= b; c ^= rot(b, 8); b += a; \ a -= c; a ^= rot(c,16); c += b; \ b -= a; b ^= rot(a,19); a += c; \ c -= b; c ^= rot(b, 4); b += a; \ } #define final(a,b,c) \ { \ c ^= b; c -= rot(b,14); \ a ^= c; a -= rot(c,11); \ b ^= a; b -= rot(a,25); \ c ^= b; c -= rot(b,16); \ a ^= c; a -= rot(c, 4); \ b ^= a; b -= rot(a,14); \ c ^= b; c -= rot(b,24); \ } typedef unsigned long Size; unsigned int hash_int4(unsigned int k) { register unsigned int a, b, c; a = b = c = 0x9e3779b9 + (unsigned int) sizeof(unsigned int) + 3923095; a += k; final(a, b, c); return c; } unsigned int hash_int8(long unsigned int k) { long int val = k; unsigned int lohalf = (unsigned int) val; unsigned int hihalf = (unsigned int) (val >> 32); lohalf ^= (val >= 0) ? hihalf : ~hihalf; return hash_int4(lohalf); } void main() { long unsigned int i; long unsigned int max_hash = 1048576; Size len = max_hash / 8; unsigned char *bitmap; int search = 500; int nset = 0; long unsigned int start; int r = 0; char str[17]; bitmap = malloc(len); memset(bitmap, 0, len); for (i = 0; i < ULONG_MAX; i++) { unsigned int h; int byte; int bit; h = hash_int8(i); if ((i > 0) && (i % 1000000000 == 0)) printf("i=%lu nset=%d\n", i, nset); if (h >= max_hash) continue; byte = h / 8; bit = h % 8; if ((bitmap[byte] & (0x01 << bit)) != 0) continue; bitmap[byte] |= (0x01 << bit); nset++; } } --------------3F757AA8719B60C565E1099D--