Fork me on GitHub
#sql
<
2020-04-20
>
g20:04:14

i’ve been hitting my head against a wall trying to figure some odd db behavior, perhaps someone could give me a hand: i have two identical insert statements with 5000 rows. executed individually they are pretty quick (ms). executed under a dorun pmap , one of them will timeout at the default of 50 s, and the other will take 4 minutes or more. what’s going on here?

g20:04:30

(timeout = lock wait timeout)

g20:04:31

here’s a description of the table:

+-------+------------+------+-----+---------+----------------+
| Field | Type       | Null | Key | Default | Extra          |
+-------+------------+------+-----+---------+----------------+
| id    | bigint(20) | NO   | PRI | NULL    | auto_increment |
| x     | binary(32) | NO   | UNI | NULL    |                |
| y     | mediumblob | YES  |     | NULL    |                |
+-------+------------+------+-----+---------+----------------+
i’m inserting x-y pairs

g20:04:15

alternatively what are some metrics i could have a look at to figure out the problem?

g20:04:14

sorry, critical point, both queries are the same. namely have the same rows

g20:04:20

(and the statement is insert ignore )

seancorfield20:04:56

Well, pmap is almost never the right solution for concurrency... but... are you trying to use a single connection across both inserts? Are you trying to do them inside a transaction?

g20:04:45

no, they are separate jdbc execute statements

g20:04:06

it’s not so much that i need pmap as i’m trying to replicate a db-layer bug that i have elsewhere, and this setup is exhibiting the same behaviour

seancorfield20:04:16

And what type of db spec / datasource are you passing in the execute?

seancorfield20:04:57

Also, which JDBC library are you using? clojure.java.jdbc or next.jdbc? And which database is this?

g20:04:03

{
      :host "localhost"
      :dbtype "mysql"
      :password "test"
      :rewriteBatchedStatements true
      :user "user"
      :allowPublicKeyRetrieval true
      :useSSL false
      :useUnicode true
      :characterEncoding "UTF-8" }

g20:04:43

clojure.java.jdbc, mysql | innodb_version | 5.7.29 |

g20:04:58

(jdbc/execute! conn (concat ["INSERT IGNORE INTO table (x,y) VALUES (?,?)"] rows) {:transaction? false :multi? true})

seancorfield20:04:21

OK. So each execute call will stand up a new connection to the DB. You'll definitely get contention in mysql from attempting two large locking inserts at the same time.

seancorfield20:04:12

Oh, so you're avoiding a transaction around each SQL op and you are trying a single batch operation with 5,000 sets of parameters in the batch...

g20:04:41

no good?

seancorfield20:04:56

rewriteBatchedStatements isn't going to help you here FYI

dpsutton20:04:12

auto_increment . could it be the key state? would using UUID make it easier?

g20:04:21

ah ok - i’ll revisit that. may be an artifact of an earlier version

g20:04:40

hmmm, interesting thought

seancorfield20:04:49

MySQL doesn't handle concurrent large inserts on a single table very well in my experience. You tend to get deadlocks.

seancorfield20:04:36

Are you wrapping the (two) calls with your own transaction? If not, why are you trying avoid c.j.j setting up a transaction?

g20:04:06

i believe it was changed to try and avoid deadlock issues, but it seems it hasn’t achieved that

g20:04:26

alright, so perhaps the solution is to re-enable that and write a bit more stuff on top to handle ‘concurrency’

g20:04:46

it does seem that enabling it at least fails fast with a deadlock error instead of spinning for a minute