Knex: 1回の実行で耇数のク゚リを実行するにはどうすればよいですか

䜜成日 2014幎04月29日  Â·  40コメント  Â·  ゜ヌス: knex/knex

';'で区切られた耇数のク゚リを実行したいずいう問題に盎面しおいたす。 䞀人の幹郚によっお、それは可胜ですか

倱敗しおいる私のテストコヌドは次のようになりたす

      var query = '' +
        'UPDATE "records_raw" ' +
        'SET "title" = ? ' +
        'WHERE "id" = ?' +
        ';' +
        'UPDATE "records_raw" ' +
        'SET "title" = ? ' +
        'WHERE "id" = ?' +
        ';';

      var bindings = [
        "x", "1",
        "y", "2"
      ];

      knex.raw(query, bindings).exec(function(err, result) {
        assert.isNotError(err);
      });

゚ラヌ

Error(cannot insert multiple commands into a prepared statement, ...

そのようなク゚リのプリペアドステヌトメントを無効にする方法はありたすか

feature request

最も参考になるコメント

すべおのアップデヌト 
multiQueryを䜜成するこずは可胜ですか
もしそうなら、どの構文を䜿甚したすか

党おのコメント40件

いいえ、2぀のステヌトメントずしお実行する必芁がありたす。

たあ、これは少し制限のある解決策です

ク゚リでtoString()を呌び出しお実行するこずもできたすが、実際にはお勧めしたせん。

knex.raw(knex.raw(query, bindings) + '').exec(function(err, result) {
  assert.isNotError(err);
});

さお、それをどうするかを芋おいきたす。基本的には、プリペアドステヌトメントをオフにしお、ク゚リ文字列ずバむンディングを持぀機胜を維持したいのですが、それが可胜かどうかはわかりたせん。これらに関連するドキュメントは芋぀かりたせんでした。

ずにかくやっおみた

knex.raw(query, bindings) + ''

しかし、それはスロヌしたす-オブゞェクトオブゞェクトにはメ゜ッド 'clone'がありたせん。

0.6.0ブランチを詊しおみたい堎合は、そこで機胜するこずはわかっおいたす。いく぀かのテストを終えたら、リリヌスする必芁がありたす。

しかし、なぜそのような単䞀の文字列を䜿甚しお2぀のク゚リステヌトメントを実行する必芁があるのでしょうか。 パッケヌゞを䜿甚する目的を損なうようなものではありたせんか

個人的には、䞀床に耇数のINSERT ... ON DUPLICATE KEY UPDATEを䜜成する必芁がありたす。 耇数の倀で挿入を実行できないため、どの行が曎新され、どの行が䜜成されたかを知りたい圱響を受ける行の倀を確認する。

Knexの制限を芋぀けた埌、私はnode.jsのさたざたなク゚リビルダヌで遊んでいたすこれは基本的にほずんどの堎合生のク゚リを䜿甚する結果になりたした。 結局、私は自分でsqlbuilderをコヌディングしたした-QSqlDemo 。 完党ではなく、本番環境にも察応しおいたせんが、基本的に私が考えおいる方法を芁玄しおいたす。

非垞にクヌルなデモです。次のリリヌスの埌にそのようなものを远加するこずを蚈画しおいたした-䞍思議なこずに、0.6ブランチを詊しおみたしたか

ここにコラボレヌションの䜙地があるのではないかず思いたす。QSQLはより堅牢なク゚リビルダヌの必芁性を満たすこずができ、Knexは接続プヌルず異なる方蚀間の疣莅の平滑化を扱いたす。

ずにかく、いい仕事、私は芋おいきたす

いいえ、0.6を詊したせんでした。ある堎所でknexを䜿甚し、別の堎所で生のク゚リを実行するコヌドがたくさんあったからです。 いく぀かの調査の結果、スタック党䜓を、保守が可胜で、機胜を即座に远加できるものに眮き換えるこずにしたした。

たあ、確かにコラボレヌションの䜙地はあるず思いたすが、最初にQSqlを安定させるには少し時間がかかりたす。 99のニヌズずナヌスケヌスに䞀臎する優れたAPIを定矩し䞀郚の構成はただ少し醜いこずがわかりたす、他のバック゚ンドを远加できるように適切な抜象化を実装するこずを意味したす。

ク゚リの配列を枡す機胜があり、結果も配列になりたすか このような単玔なものはかっこいいでしょう、それを行うためにasync.parallelのようなものを䜿甚するこずができたす

@niftylettuce Bluebirdには、すぐに䜿甚できる「async.parallel」機胜がすでに付属しおいたす。 しかし、これは問題ではありたせん。 1回の実行でコマ分離ク゚リを実行する方法が本圓に必芁です。

マヌクするだけでは䞍可胜です

    multipleStatements: true

自分の構成の接続ブロック内
䟋えば

    connection: {
        host: 'localhost',
        user: 'superSecret',
        password: 'notGonnaTell',
         port: 8889,
        database: 'babelverse_core',
        multipleStatements: true
    }

さお、ここの誰かが興味を持っおいるなら-私はこれを可胜にするために次のリファクタリングでいく぀かの新しいこずに取り組んでいたす。

これに理想的なAPIは䜕でしょうか...単䞀のチェヌンが必芁ですか

knex
  .update('records_raw')
  .set({title: x}).where({id: 1})
  .end()
  .update('records_raw')
  .set({title: y}).where({id: 2})
  .spread((resultA, resultB) => {

  })

たたはもっず䌌たようなもの

knex.multiQuery([
  knex.update('records_raw').set({title: x}).where({id: 1})
  knex.update('records_raw').set({title: y}).where({id: 2})
]).spread((resultA, resultB) => {

})

たた、セミコロンで分割するこずにより、 knex.rawケヌスを自動的に機胜させる可胜性を怜蚎しおいたす。

生のク゚リでセミコロンを分割するこずは玠晎らしいスタヌトです。

珟圚、挿入前に削陀が完了しないずいう問題が発生しおいるため、重耇キヌ゚ラヌがスロヌされたす。

私は次のようなこずをしおいたす

knex("mytable")
.where({
  id: 32423
})
.del()
.then( ->
  knex("mytable")
  .insert()
 ..... 

あなたは芁点を理解したす。

デルは時間内に完了したせん。

@tgriesser私の投祚はknex.multiQueryです

@tgriesser単䞀のク゚リで耇数のステヌトメントを実行する機胜に関する曎新はありたすか を奜む

.update 'records_raw'
.set{titlex}。where{id1}
。終わり
.update 'records_raw'
.set{titley}。where{id2}
.thenfunctionresult{
result [0] //結果1
result [1] //結果2
}
.catchfunctionerr{
console.logerr;
};

+1

セミコロンで適切な分割を行うには、方蚀固有のパヌサヌを䜿甚しお生のク゚リ党䜓を解析する必芁がありたす。 具䜓的には、文字列に;が含たれおいる堎合、それらは無芖する必芁がありたす。 解析するのが簡単ではない有効なSQLの2぀の䟋を次に瀺したす。

-- generic SQL
SELECT * FROM book WHERE title = 'Lord of the Rings; The Fellowship of the Ring';
-- MySQL specific
CREATE PROCEDURE dorepeat(p1 INT)
  BEGIN
    SET <strong i="9">@x</strong> = 0;
    REPEAT SET <strong i="10">@x</strong> = <strong i="11">@x</strong> + 1; UNTIL <strong i="12">@x</strong> > p1 END REPEAT;
  END

たた、最初のケヌスでは2぀のステヌトメントが䜜成されるため、コヌドは分割の空の結果を考慮する必芁があるこずに泚意しおください。

正盎なずころ、党䜓ずしお、これは悪い考えだず思いたす。 SQLむンゞェクションが発生し、ク゚リが正しく分割されない可胜性が非垞に高くなりたす。

たた、耇数のステヌトメントを実行する堎合、ほずんどの堎合、同じトランザクションでそれを実行する必芁がありたす。 Knexは、 .transacting(function(transaction) { /* code */ })構文を䜿甚しお、この問題をすでに非垞にうたく解決しおいたす。 トランザクションが䞍芁なたれなケヌスでは、bluebirdを䜿甚しおknexステヌトメントを結合し、結果を取埗できたす。

したがっお、これらの問題のために、これは起こらないはずだず私の意芋です。

-1

たた、耇数のステヌトメントを実行する堎合、ほずんどの堎合、同じトランザクションでそれを実行する必芁がありたす。 Knexは、 .transacting(function(transaction) { /* code */ })構文を䜿甚しお、この問題をすでに非垞にうたく解決しおいたす。 トランザクションが䞍芁なたれなケヌスでは、bluebirdを䜿甚しおknexステヌトメントを結合し、結果を取埗できたす。

経隓から、特定のケヌスでは、これら2぀のアプロヌチず、1぀のコマンドずしおサヌバヌに耇数の倀をバッチ凊理するこずの間に_巚倧な_パフォヌマンスの違いがあるこずがわかりたす。

クリヌンに実装するのは非垞に難しいこずを理解しおいたす。そのため、ただ実装されおいたせんが、この問題により、プロゞェクトでのknexの䜿甚が倧幅に制限されおいたす。

私も同様の問題を抱えおいお、それを解決するこずができたした。 こちらをご芧ください。 https://github.com/tgriesser/knex/issues/1075

この機胜のナヌスケヌスが芋圓たりたせん。 修正されないので、このチケットを閉じたいず思いたす。 同じ接続で実行されおいるク゚リの順序に䟝存しおいる堎合は、トランザクションを䜿甚するこずをお勧めしたす。

この「耇数のク゚リ」の䜿甚法を私たちが望んでいるものにしたこずの1぀は、堎合によっおはパフォヌマンスが向䞊する可胜性があるずいうこずです。 サヌバヌずの間ですべおのク゚リず結果を通信するために必芁なラりンドトリップが少なくお枈みたす。

しかし、枬定可胜なナヌスケヌスが利甚できるわけではありたせん。 過去の経隓/蚘憶からのみ話す...

@ jurko-gospodnetic接続プヌルがない堎合がありたす。 プヌルを䜿甚するず、耇数のク゚リを送信するこずは、基本的に、䜜成枈みのTCP゜ケットにデヌタを配眮するだけです。 たた、パフォヌマンスがTCPバッファヌが十分に満たされおいないこずに䟝存しおいる堎合は、knexはすでに遅すぎたす:)その堎合は、ドラむバヌを盎接䜿甚するこずをお勧めしたす。

@ jurko-gospodneticが5月20日にコメントしたした

この「耇数のク゚リ」の䜿甚法を私たちが望んでいるものにしたこずの1぀は、堎合によっおはパフォヌマンスが向䞊する可胜性があるずいうこずです。 サヌバヌずの間ですべおのク゚リず結果を通信するために必芁なラりンドトリップが少なくお枈みたす。

この特定の理由から、゚ンタヌプラむズグレヌドのプロゞェクトでnode-mysqlmysqljsを䜿甚しおい

node-mysqlmysqljsドラむバヌの耇数ステヌトメントのク゚リ機胜を利甚するこずで、このような操䜜のパフォヌマンスが倧幅に向䞊したす。

Knexがこれをサポヌトしおいない堎合、それは私にずっおショヌトッパヌになるかもしれたせん。 だから私はこのスレッドを埩掻させおそれだけを尋ねたす。

Knex.jsでは、1぀のステヌトメントでの耇数のク゚リがサポヌトされるようになりたしたか

@nicholaswminは、「倧幅なパフォヌマンスの向䞊」ずはどういう意味ですか この方法で耇数のク゚リを送信する方が、同じ接続を介しお耇数のク゚リを送信するよりもはるかに効率的ですか ベンチマヌクはありたすか

@elhiguベンチマヌクはありたせんが、すぐに私はこれを蚀うこずができたす

DBぞの1回の呌び出しすべおのステヌトメントが含たれおいるにより、server-dbネットワヌクのラりンドトリップが排陀されたす。

䞀方、同じ接続を介しお耇数のク゚リを送信するこずは特効薬ではありたせん。 この゜リュヌションは、非トランザクションフロヌでのみ機胜したす。この問題を参照しおください

@nicholaswmin倧量の小さなク゚リを送信しおいお、ほずんど無芖されおいるか、小さな結果ですか その堎合、ドラむバヌが各TCPパケットに耇数のク゚リをパックできるため、違いが目立぀可胜性があるず思いたす。そうしないず、各TCPパケットのほずんどがヘッダヌになり、ペむロヌドが非垞に少なくなりたす。

このようなパフォヌマンスの違いは、ネットワヌクトラフィックの量からでも簡単に枬定できるはずです。

ドラむバヌが、前の呌び出しの結果を最初に埅たずに、別々のconnection.query呌び出しからDBぞの耇数のク゚リの送信をサポヌトしおいるかどうかはわかりたせん。 もしそうなら、耇数のconnection.query送信するか、mysqlドラむバヌでサポヌトされおいる単䞀のマルチク゚リを送信するかでTCPトラフィックに倧きな違いはないはずです。

@elhiguこれらは確かに小さなク゚リですが、トランザクション/ク゚リチェヌンのさらに䞋流で䜿甚できるように結果が必芁です。

デバッグたたは同様のオプションを介しお送信されおいるTCPパケットを確認する方法はありたすか 送信されるク゚リ自䜓ではなく、実際のパケット。

ナヌスケヌス

システム内のナヌザヌのデヌタを曎新するずきに、そのナヌザヌの監査蚌跡䜕が倉曎されたかを蚈算したいず思いたす。

// # PSEUDOCODE

// get current data of user
getUserData();
// set data of user
setUserData()
// get new data of user
getUserData()
// compute the audit trail by comparing the difference between before-set/after-set datums
computeAuditTrail(previousData, newData);

䞊蚘の各呌び出しは耇数のDB呌び出しを行うため、ご想像のずおり、これらは倚くのネットワヌクラりンドトリップです。

1806で述べたように、シヌケンシャルである必芁のないク゚リにPromise.all()を䜿甚するこずで、これを回避できたすほずんどの堎合、 getData/setDataのDB呌び出しはシヌケンシャルである必芁はありたせん。

ク゚リはプヌルからのさたざたな接続で送信できるため、これは非トランザクションフロヌで機胜したす。 トランザクションを䜿甚しお䞊蚘のフロヌを実行するずすぐに、ク゚リが単䞀の接続で送信されるため、速床が䜎䞋したす玄4倍。

補足ずしお、私はMSSQLを䜿甚しおいたす。

Wiresharkは、ネットワヌクトラフィックの分析に䜿甚される非垞に䞀般的なクロスプラットフォヌムツヌルです。

ノヌドでそのレベルを確認する方法はないず思いたす。

1぀の方法は、iptrafなどを䜿甚しお、1぀のク゚リにパックされた、たたはドラむバヌに個別に枡された同じ量のク゚リを送信するずきに、送受信されたデヌタの量を枬定するこずです。

multiQuery構文を芋たいです。

すべおのアップデヌト 
multiQueryを䜜成するこずは可胜ですか
もしそうなら、どの構文を䜿甚したすか

var knex = require("knex");
var _ = require("lodash");
var Promise = require("bluebird");

var knex = require('knex')({
    client: 'sqlite3',
    connection: {
        filename: "./data.sqlite"
    }
});

// Create Schema
let createScript = `

CREATE TABLE Class ( 
    Id                   integer NOT NULL  ,
    Name                 varchar(100)   ,
    CONSTRAINT Pk_Classes_Id PRIMARY KEY ( Id )
 );

CREATE TABLE Material ( 
    Id                   integer NOT NULL  ,
    Description          varchar(500)   ,
    CONSTRAINT Pk_Material_Id PRIMARY KEY ( Id )
 )

-- ... and so on (leave off the last semi or remove it later) ... 

`;

let statementPromises = _.map(createScript.split(';'), (statement) => {
    return knex.raw(statement);
});

Promise.all(statementPromises).then(function() {
    console.log('Schema generated. Populating...');

     // ...

これは単なるルヌプであり、耇数のリク゚ストを1぀にたずめたものではなく、䜎速です。

@mscheffer質問は

';'で区切られた耇数のク゚リを実行したいずいう問題に盎面しおいたす。 䞀人の幹郚によっお、それは可胜ですか

私の答えはどれを解決したすか。 あなたがより速くより良い解決策を持っおいるならば、それを提䟛しおください。

@VictorioBerra ;からの分割は、文字列リテラルずコメント内に;が存圚する可胜性があるため、通垞は機胜したせん。 デヌタダンプを読み蟌んでいる堎合、SQLダンプコヌドをsqliteシェルにパむプするのが簡単な方法だず思いたす。 残念ながら、むンメモリデヌタベヌスは単䞀の接続であるため、これは機胜したせん。

たた、テンプレヌト文字列内でSQL文字列を䜜成し、それを分割する堎合も、 knex.schema.*ビルダヌを䜿甚するず、実質的に同じこずができたすが、より安党になりたす。

私の知る限り、すべおの方蚀ドラむバヌに察しお1぀のコマンドで耇数のク゚リを実行するずいうこの機胜を実珟する方法はありたせん。 そのサポヌトがあったのはmysqlずoracledbたたはmssqlだったず思いたすが、mysqlを䜿甚するず、最埌のク゚リの結果だけが応答ずしお返されたすただし、問題ない可胜性がありたす。

耇数のク゚リを䜿甚しおデヌタを倉曎する堎合は、トランザクションを䜿甚しお、それらが連続しお実行されるこずを確認できるようにしおください。

RAWSQLを䜿甚した耇数のク゚リ実行
私は、knex移行の1぀がCREATE DATABASE連続しお耇数回実行する必芁がある同様の状況に遭遇したした。 ク゚リをセミコロンで区切るこずを望みたしたが、knexは構文゚ラヌをスロヌしたした。 その解決策は、接続オブゞェクトに"multipleStatements": trueを含めるこずです。そのため、その最終結果は次のようになりたす。

"host": "192.168.x.x",
"user": "userLogin",
"password": "userPassword",
"database": "schemaToUse",
"multipleStatements": true

その埌、次のような生のステヌトメントを䜿甚できたす。

return knex.raw("CREATE DATABASE schema0; CREATE DATABASE schema1; CREATE DATABASE schema2")
   .then((result) => {
   })
   .catch((error) => {
   });

KNEXク゚リビルダヌを䜿甚した耇数のク゚リ実行
生のSQLを自分で䜜成する代わりに、knexク゚リビルダヌを䜿甚する必芁がある堎合は、 Knex.QueryBuilderの結果を文字列に倉換しおから、耇数のク゚リを結合する必芁がありたす。 これが1぀の䟋です

// Suppose that we wanted to add 100 currency for all players in multiple games
const addCurrency = 100;
const updateCurrency = { currency: "currency + " + addCurrency };
const queries = [
   knex.table("game0.stats").update(updateCurrency),
   knex.table("game1.stats").update(updateCurrency),
   knex.table("game2.stats").update(updateCurrency),
];
const multiQuery = queries.join(";");
console.log(multiQuery);
return knex.raw(multiQuery)
   .then((result) => {
   })
   .catch((error) => {
   });

これは、連続しお実行する必芁のある冗長なク゚リを䜜成する際の人的゚ラヌを枛らすのにも圹立ちたす。 繰り返したすが、このようなものでは、トランザクションでラップするこずをお勧めしたす。

これはほずんどdbドラむバヌによっお制限されおいるので、これを閉じるこずができるず思いたす。 少なくずも適切な機胜芁求が必芁です。

@AksharaKarikalan耇数のサブク゚リを実行し、それらの間で枛算を行ったずしおも、ク゚リは1぀だけです。 そこで、この問題に関係のないコメントを削陀したした。 Stackoverflowは、knexの䜿甚リク゚ストに適した堎所です。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡