mariadb-corporation / mariadb-connector-nodejs

MariaDB Connector/Node.js is used to connect applications developed on Node.js to MariaDB and MySQL databases. MariaDB Connector/Node.js is LGPL licensed.
GNU Lesser General Public License v2.1
368 stars 91 forks source link

Optimal way to use pools? #159

Closed Turbine1991 closed 3 years ago

Turbine1991 commented 3 years ago

I'm a little unsure of how the underlying pools are implemented/should be used.

Thank you.

rusher commented 3 years ago

Hi @Turbine1991

If your application has to execute multiple queries, it's better to get a connection, executes the queries, then release the connection. like :

    const connection = await pool.getConnection();
    // execute multiple queries
    await connection.query("INSERT INTO ...");
    await connection.query("INSERT INTO ...");
    connection.release(); //release to pool

Will a new connection have to be made every time I release the connection, incurring a connection delay? or will it reuse an existing released connection in the pool?

When releasing a connection from pool (using conn.release()), pool stored the connection for next request. Internally, pool can release connection after some time beeing not used (option idleTimeout), but it will recreate connection if needed.

Turbine1991 commented 3 years ago

Thank you for responding.

Am I right to assume that connection.batch(sql, values) is effectively equivalent to your example of dispatching multiple queries on a single connection?

Also, which facility may execute queries out-of-order, as opposed to sequentially? Pool connections, batch function?

Cheers.

rusher commented 3 years ago

Am I right to assume that connection.batch(sql, values) is effectively equivalent to your example of dispatching multiple queries on a single connection?

That depends :)

Batch has 3 different implementations, driver will choose the fastest one.

With MariaDB server 10.2+, a specific BULK command is send. from far the faster way If MariaDB server before 10.2 or MySQL server, rewrite query if possible (for INSERT) INSERT into t1 VALUES (?) => will be rewritten INSERT into t1 VALUES ('val1'), ('val2'), ... if not, just a basic loop.

rusher commented 3 years ago

to answer your second question, for queries out-of-order you need pool :

In the example before :

const connection = await pool.getConnection();
    // execute multiple queries
    await connection.query("INSERT INTO ...");
    await connection.query("INSERT INTO ...");
    connection.release(); //release to pool

=> connector send first "INSERT INTO ..." to server. <= server send result of first INSERT => connector send second "INSERT INTO ..." to server. <= server send result of second INSERT

Same example without on await:

const connection = await pool.getConnection();
    // execute multiple queries
    connection.query("INSERT INTO ...");
    await connection.query("INSERT INTO ...");
    connection.release(); //release to pool

query are send in order on one connection, then will be trait accordingly:

=> connector send first "INSERT INTO ..." to server. => connector send second "INSERT INTO ..." to server. <= server send result of first INSERT <= server send result of second INSERT

same using pool directly

    // execute multiple queries
await Promise.all([
  pool.query("INSERT INTO ..."),
  pool.query("INSERT INTO ...")
]);

Those to inserts will be send on different connections.

Turbine1991 commented 3 years ago

Thank you for all this info. I really appreciate it.

One last question, what happens when it loses connection to the server? Will it halt all transactions until a timeout? Reattempt? Or just throw an error?

The reason is that I had an issue with MariaDB restarting itself once-twice a day (presumably because it consumed too much of the 1gb ram). In the npm library mysql2, it wouldn't reattempt the transaction, causing my program to fail. Is there any form of reattempt interval available?

rusher commented 3 years ago

It's a little bit more complex than that :/ If there is a network failure, there isn't any TCP FIN / RST that properly indicate that socket ended, so server and connector doesn't know about socket state until trying to read/write from it.

So: From driver point of view, there will be reads/new query quickly => driver will then throw an error without reattempt. There is no failover implementation for now. From server point of view: nothing is received on the connection that has a transaction, so it stay to that point until reaching @@wait_timeout (i'm not a specialist of server, there might be other option involved there).

If problem is that server fails, driver will throw an error on next query ( or during the query if there was one running). Reattempt have to be programmatically implemented.

I've missed the question. sorry for delay !