Queries which rely on performing certain mathematical operations on timestamps run significantly slower than they could because of a lot of time spent locking and unlocking mutexes. The problem is compounded on Windows because pthread_mutex_lock() and pthread_mutex_unlock() are implemented using WaitForSingleObject() and ReleaseMutex(), which both involve a user<->kernel transition. The operations I have observed to have this problem so far are subtraction of two timestamps and extract(hour from ts).
Reproducible: Always
Steps to Reproduce:
Create a file with 10000 lines of timestamps in it, all the same
create table times (t timestamp);
copy 10000 records into times from 'times.txt';
select count(*) from times A,times B where A.t-B.t<>0;
Actual Results:
The select query takes 428s to complete (on a Sandy Bridge @ 3.4GHz).
Expected Results:
The identical query "select count(*) from times A,times B where A.t<>B.t;" takes 910ms to complete.
System timing says that mserver5 spends 74% of its time in kernel mode when executing that slow query. Stack trace of a random mutex lock mid-query:
FYI, the query above is obviously an artificial test-case for this bug report. The actual query I was doing was select * from bigtable where endtime-starttime>20000;
Date: 2012-05-22 22:48:11 +0200
From: Richard Hughes <>
To: GDK devs <>
Version: 11.11.5 (Jul2012)
Last updated: 2013-02-19 13:17:59 +0100
Comment 17275
Date: 2012-05-22 22:48:11 +0200
From: Richard Hughes <>
User-Agent: Opera/9.80 (Windows NT 6.1; WOW64; U; en) Presto/2.10.229 Version/11.64
Build Identifier: v11.9.1 "Apr2012" amd64
Queries which rely on performing certain mathematical operations on timestamps run significantly slower than they could because of a lot of time spent locking and unlocking mutexes. The problem is compounded on Windows because pthread_mutex_lock() and pthread_mutex_unlock() are implemented using WaitForSingleObject() and ReleaseMutex(), which both involve a user<->kernel transition. The operations I have observed to have this problem so far are subtraction of two timestamps and extract(hour from ts).
Reproducible: Always
Steps to Reproduce:
Actual Results:
The select query takes 428s to complete (on a Sandy Bridge @ 3.4GHz).
Expected Results:
The identical query "select count(*) from times A,times B where A.t<>B.t;" takes 910ms to complete.
System timing says that mserver5 spends 74% of its time in kernel mode when executing that slow query. Stack trace of a random mutex lock mid-query:
libbat!pthread_mutex_lock [gdk\gdk_system.c @ 295]
libbat!incref+0x109 [gdk\gdk_bbp.mx @ 2237]
libmonetdb5!BATdescriptor+0x66 [gdk\gdk.h @ 2507]
libmonetdb5!BKCinsert_bun+0x1e [monetdb5\modules\kernel\bat5.mx @ 1463]
libmonetdb5!runMALsequence+0x8c93 [monetdb5\mal\mal_interpreter.mx @ 1967]
libmonetdb5!callMAL+0x16b [monetdb5\mal\mal_interpreter.mx @ 2591]
lib_sql!SQLexecutePrepared+0x20b [sql\backends\monet5\sql_scenario.c @ 1642]
lib_sql!SQLengineIntern+0xb6 [sql\backends\monet5\sql_scenario.c @ 1695]
libmonetdb5!runScenarioBody+0x21e [monetdb5\mal\mal_scenario.c @ 574]
libmonetdb5!runScenario+0x22 [monetdb5\mal\mal_scenario.c @ 601]
libmonetdb5!MSserveClient+0xe0 [monetdb5\mal\mal_session.c @ 439]
libbat!thread_starter+0x10 [gdk\gdk_system.c @ 172]
kernel32!BaseThreadInitThunk+0xd
ntdll!RtlUserThreadStart+0x1d
FYI, the query above is obviously an artificial test-case for this bug report. The actual query I was doing was select * from bigtable where endtime-starttime>20000;
sql>explain select count(*) from times A,times B where A.t<>B.t;
+----------------------------------------------------------------------+
| mal |
+======================================================================+
| function user.s28_1{autoCommit=true}():void; |
| X_23 := nil:wrd; |
| barrier X_46 := language.dataflow(); |
| X_2 := sql.mvc(); |
| X_10:bat[:oid,:timestamp] := sql.bind(X_2,"sys","times","t",0); |
| X_8:bat[:oid,:timestamp] := sql.bind(X_2,"sys","times","t",2); |
| X_12 := algebra.kdifference(X_10,X_8); |
| X_13 := algebra.kunion(X_12,X_8); |
| X_4:bat[:oid,:timestamp] := sql.bind(X_2,"sys","times","t",1); |
| X_14 := algebra.kunion(X_13,X_4); |
| X_15:bat[:oid,:oid] := sql.bind_dbat(X_2,"sys","times",1); |
| X_16 := bat.reverse(X_15); |
| X_17 := algebra.kdifference(X_14,X_16); |
| X_18 := bat.reverse(X_17); |
| X_19 := algebra.antijoin(X_17,X_18); |
| X_20 := algebra.markT(X_19,0@0:oid); |
| X_21 := bat.reverse(X_20); |
| X_22 := algebra.leftjoin(X_21,X_14); |
| X_23 := aggr.count(X_22); |
| exit X_46; |
| sql.exportValue(1,"sys.a","L1":str,"wrd",64,0,6,X_23,""); |
| end s28_1; |
+----------------------------------------------------------------------+
sql>explain select count(*) from times A,times B where A.t-B.t<>0;
+----------------------------------------------------------------------+
| mal |
+======================================================================+
| function user.s29_1{autoCommit=true}(A0:lng):void; |
| X_27 := nil:bat[:oid,:timestamp]; |
| X_31:bat[:oid,:timestamp] := nil:bat[:oid,:timestamp]; |
| barrier X_62 := language.dataflow(); |
| X_3 := sql.mvc(); |
| X_11:bat[:oid,:timestamp] := sql.bind(X_3,"sys","times","t",0); |
| X_9:bat[:oid,:timestamp] := sql.bind(X_3,"sys","times","t",2); |
| X_13 := algebra.kdifference(X_11,X_9); |
| X_14 := algebra.kunion(X_13,X_9); |
| X_5:bat[:oid,:timestamp] := sql.bind(X_3,"sys","times","t",1); |
| X_15 := algebra.kunion(X_14,X_5); |
| X_16:bat[:oid,:oid] := sql.bind_dbat(X_3,"sys","times",1); |
| X_17 := bat.reverse(X_16); |
| X_18 := algebra.kdifference(X_15,X_17); |
| X_23 := algebra.project(X_18,0:int); |
| X_19 := bat.reverse(X_18); |
| X_20 := bat.reverse(X_19); |
| X_21 := algebra.project(X_20,0:int); |
| X_22 := bat.reverse(X_21); |
| X_24 := algebra.join(X_23,X_22); |
| X_25 := algebra.markT(X_24,0@0:oid); |
| X_26 := bat.reverse(X_25); |
| X_27 := algebra.leftjoin(X_26,X_15); |
| X_28 := bat.reverse(X_24); |
| X_29 := algebra.markT(X_28,0@0:oid); |
| X_30 := bat.reverse(X_29); |
| X_31:bat[:oid,:timestamp] := algebra.leftjoin(X_30,X_15); |
| exit X_62; |
| X_70 := bat.new(nil:oid,nil:lng); |
| barrier (X_73,X_74,X_75) := bat.newIterator(X_27); |
| X_77 := algebra.find(X_31,X_74); |
| X_79 := mtime.diff(X_75,X_77); |
| bat.insert(X_70,X_74,X_79); |
| redo (X_73,X_74,X_75) := bat.hasMoreElements(X_27); |
| exit (X_73,X_74,X_75); |
| X_31:bat[:oid,:timestamp] := nil:bat[:oid,:timestamp]; |
| X_32:bat[:oid,:lng] := X_70; |
| X_35 := algebra.antiuselect(X_32,A0); |
| X_36 := algebra.markT(X_35,0@0:oid); |
| X_37 := bat.reverse(X_36); |
| X_38 := algebra.leftjoin(X_37,X_27); |
| X_39 := aggr.count(X_38); |
| sql.exportValue(1,"sys.a","L1":str,"wrd",64,0:int,6,X_39,""); |
| end s29_1; |
+----------------------------------------------------------------------+
Comment 17276
Date: 2012-05-22 23:10:56 +0200
From: @sjoerdmullender
I guess we need a bulk version of mtime.diff.
Comment 17704
Date: 2012-08-27 11:19:25 +0200
From: @sjoerdmullender
Changeset 536a859ef7d7 made by Sjoerd Mullender sjoerd@acm.org in the MonetDB repo, refers to this bug.
For complete details, see http//devmonetdborg/hg/MonetDB?cmd=changeset;node=536a859ef7d7
Changeset description:
Comment 17705
Date: 2012-08-27 11:22:23 +0200
From: @sjoerdmullender
I implemented bulk versions of mtime.diff which should solve the problem. The implementation will be in the next feature release (probably October).
Comment 18514
Date: 2013-02-19 13:17:59 +0100
From: @sjoerdmullender
Feb2013 has been released.
The text was updated successfully, but these errors were encountered: