10

これを行うための最速の方法は何ですか:

  • 1 つのテーブル、事前に入力できない参照はありません (つまり、参照キーが 1 つありますが、すべてのデータが入力されています)。
  • たくさんのデータ。APIを介して動的に入力される、1日あたり数億行について話します
  • 要求は、ほぼリアルタイムのシナリオで可能な限り早く処理する必要があります (つまり、1 日 1 回のアップロードのためにファイルに書き出す必要はありません)。2 秒が通常の最大遅延です
  • データ/アプリケーションと SQL Server 用に別のマシン

私が今していること:

  • 最大 32*1024 行を配列に集約してから、キューに入れます。
  • 2 ~ 3 スレッドでキューを読み取ります。SqlBulkCopy を使用してデータベースに挿入します。

1 秒あたり約 60k ~ 75k 行がインポートされますが、これは十分ではありませんが、かなり近い値です。250.000行を達成したいと思っています。

これまでのところ、実際には何も使用されていません。私は 20% の時間「ネットワーク I/O」ブロックを取得し、1 つのコアで 80% の CPU 側をロードしました。ディスクは 7 mb ~ 14 mb を書き込んでおり、ほとんどアイドル状態です。6 raptors の RAID 10 の平均キュー長は.... 0.25 です。

これをスピードアップする方法を知っている人はいますか?より高速なサーバー (これまでのところ、仮想、8 GB RAM、4 コア、データ用の物理ディスク パス スルー)。


いくつかの説明を追加します:

  • これは、2008 R2 サーバー上の 2008 R2 Enterprise SQL Server です。マシンには 4 コア、8 GB RAM があります。すべて64ビット。80% の負荷平均は、約 20% の CPU 負荷を示すこのマシンからのものです。
  • テーブルは単純で、主キーはなく、リレーショナル参照 (計測器参照) のインデックスと一意 (一連の計測器内であるため、これは強制されません) タイムスタンプのみです。
  • テーブルのフィールドは次のとおりです: タイムスタンプ、インストゥルメント リファレンス (強制的な外部キーなし)、データ タイプ (char 1、投稿されたデータを示す文字数の 1 つ)、価格 (double)、ボリューム (int)。ご覧のとおり、これは非常に薄いテーブルです。問題のデータは、金融商品のティック データです。
  • 質問はハードウェアなどについてもです。主に、実際のボトルネックが見られないためです。私は複数のトランザクションに挿入していますが、それは私に利益をもたらしますが、それは小さなものです。ディスク、CPU は大きな負荷を示しておらず、ネットワーク io 待機は高くなっています (300 ミリ秒/秒、現時点では 30%) が、これは 2 つのサーバーで JSUT を実行し、すべてを実行するのに十分なコアを備えた同じ仮想化プラットフォーム上にあります。私は「別のサーバーを購入する」ことにほとんどオープンですが、最初にボトルネックを特定したいと思います....特に、結局のところ、ボトルネックが何であるかを把握していないことを考えると. ロギングは関係ありません。一括挿入はデータとしてデータ ログに記録されません (クラスター化されたインデックスはありません)。

たとえば、バイト (tinyint) によって、たとえば 16 個のテーブルでインストゥルメント ユニバースを分割し、同時に最大 16 個の挿入を行うことで、垂直分割が役立ちますか? 実際には、データはさまざまな取引所から取得されるため、取引所ごとにパーティションを作成できます。これは自然な分割フィールドになります (これは実際には計測器にありますが、ここでこのデータを複製することができます)。


いくつかの明確化: 速度がさらに高速になり (90k)、マシン間のネットワーク IO によって明らかに制限されました。これは VM の切り替えである可能性があります。

私が今していることは、32k行ごとに接続を行い、一時テーブルを作成し、SqlBUlkdCopyでこれに挿入し、次に1つのSQLステートメントを使用してメインテーブルにコピーすることです-メインテーブルのロック時間を最小限に抑えます.

現在、ほとんどの待機時間はネットワーク IO にあります。VMが賢明な問題に遭遇したようです。今後数か月で物理ハードウェアに移行します ;)

4

6 に答える 6

4

1 秒あたり 7 万行を管理できれば、これまでのところ非常に幸運です。しかし、それはあなたが非常に単純なスキーマを持っているからだと思います。

この種の負荷についてあなたが尋ねるなんて信じられない

  • 仮想サーバー
  • 単一の配列
  • SATA ディスク

ネットワークと CPU は共有され、IO は制限されています。すべてのリソースを使用することはできません。表示される負荷統計はあまり役に立ちません。表示されるネットワーク負荷は 2 つの仮想サーバー間のトラフィックであると思われます。これを解決すると、IO バウンドになるでしょう。

先に進む前に、この35K tps からの 10 の教訓を読んでください。彼は仮想ボックスを使用していませんでした。

ボリュームを増やしたい場合、SAN も DR 機能もないと仮定すると、次のようになります。

  • 2 台の大きな物理サーバーを購入し、CPU RAM の種類は無関係、最大 RAM、x64 インストールに進む
  • ディスク + コントローラ = 最速のスピンドル、最速の SCSI。または驚異的な優れた NAS
  • 1000MB + NIC
  • データベース専用の1 つのログ ファイル用に 6 ~ 10 個のディスクを備えた RAID 10
  • データファイル用の残りのディスク RAID 5 または RAID 10

参考までに、当社のピーク負荷は 1 時間あたり 1,200 万行 (16 コア、16 GB、SAN、x64) ですが、負荷は複雑です。定員に達していません。

于 2011-01-27T20:39:26.277 に答える
1

テーブル上になしで実行できるインデックスはありますか?編集:あなたがタイプしている間に尋ねる。

価格を整数に変換してから、クエリで1000などで割ることはできますか?

于 2011-01-20T13:59:05.203 に答える
1

テーブルにpkを追加してみましたか?それは速度を改善しますか?

タリーテーブルを使用してhttp://www.sqlservercentral.com/articles/T-SQL/62867/からcsvデータをインポートするセットベースの方法もあります(下部にあり、無料登録が必要ですが、それだけの価値があります)。

あなたはそれを試してそのパフォーマンスをテストしたいかもしれません...小さなタリーが適切にインデックス付けされたタリーテーブルを使って。

于 2011-01-20T14:05:04.957 に答える
1

ここで読んだ回答から、コードの問題ではなく、ハードウェアの問題が本当にあるようです。理想的には、より多くのディスク I/O またはネットワーク帯域幅を利用できるようにするか、データベースをホストする同じ仮想マシンでプログラムを実行することによって、パフォーマンスを向上させることができます。

ただし、テーブル パラメーターの挿入はビッグ データ転送に最適であるという考えを共有したいと思います。SqlBulkCopy も同様に高速に見えますが、柔軟性が大幅に低下します。

このトピックに関する記事をここに書きました: http://www.altdevblogaday.com/2012/05/16/sql-server-high-performance-inserts/

全体的な答えは、大まかにテーブル型を作成したいということです:

CREATE TYPE item_drop_bulk_table_rev4 AS TABLE (
    item_id BIGINT,
    monster_class_id INT,
    zone_id INT,
    xpos REAL,
    ypos REAL,
    kill_time datetime
)

次に、ストアド プロシージャを作成して、テーブル パラメーターから実際のテーブルに直接コピーするため、中間の手順が少なくなります。

CREATE PROCEDURE insert_item_drops_rev4
    @mytable item_drop_bulk_table_rev4 READONLY
AS

INSERT INTO item_drops_rev4 
    (item_id, monster_class_id, zone_id, xpos, ypos, kill_time)
SELECT 
    item_id, monster_class_id, zone_id, xpos, ypos, kill_time 
FROM 
    @mytable

SQL Server のコード ビハインドは次のようになります。

DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("item_id", typeof(Int64)));
dt.Columns.Add(new DataColumn("monster_class_id", typeof(int)));
dt.Columns.Add(new DataColumn("zone_id", typeof(int)));
dt.Columns.Add(new DataColumn("xpos", typeof(float)));
dt.Columns.Add(new DataColumn("ypos", typeof(float)));
dt.Columns.Add(new DataColumn("timestamp", typeof(DateTime)));

for (int i = 0; i < MY_INSERT_SIZE; i++) {
    dt.Rows.Add(new object[] { item_id, monster_class_id, zone_id, xpos, ypos, DateTime.Now });
}

// Now we&#039;re going to do all the work with one connection!
using (SqlConnection conn = new SqlConnection(my_connection_string)) {
    conn.Open();
    using (SqlCommand cmd = new SqlCommand("insert_item_drops_rev4", conn)) {
        cmd.CommandType = CommandType.StoredProcedure;

        // Adding a "structured" parameter allows you to insert tons of data with low overhead
        SqlParameter param = new SqlParameter("@mytable", SqlDbType.Structured);
        param.Value = dt;
        cmd.Parameters.Add(param);
        cmd.ExecuteNonQuery();
    }
}
于 2012-07-18T17:43:25.627 に答える
1

それはすべて遅いです。

しばらく前に、同様の問題を解決しました (DB に数万の価格データを挿入します。時間枠あたり約 50K であったことを覚えています。約 8 つの時間枠があり、すべてが :00 に衝突したため、約 400K レコードでした)。非常に高速に動作しました (MS SQL 2005)。それが今日どのように機能するか想像してみてください (SQL 2012):

<...init...>
if(bcp_init(m_hdbc, TableName, NULL, NULL, DB_IN) == FAIL)
    return FALSE;

int col_number = 1;

// Bind columns
if(bcp_bind(m_hdbc, (BYTE *)&m_sd.SymbolName, 0, 16, (LPCBYTE)"", 1, 0, col_number++) == FAIL) return FALSE;
if(bcp_bind(m_hdbc, (BYTE *)&m_sd.Time, 0, 4, 0, 0, 0, col_number++) == FAIL) return FALSE;
if(bcp_bind(m_hdbc, (BYTE *)&m_sd.Open, 0, 8, 0, 0, 0, col_number++) == FAIL) return FALSE;
if(bcp_bind(m_hdbc, (BYTE *)&m_sd.High, 0, 8, 0, 0, 0, col_number++) == FAIL) return FALSE;
if(bcp_bind(m_hdbc, (BYTE *)&m_sd.Low, 0, 8, 0, 0, 0, col_number++) == FAIL) return FALSE;
if(bcp_bind(m_hdbc, (BYTE *)&m_sd.Close, 0, 8, 0, 0, 0, col_number++) == FAIL) return FALSE;
if(bcp_bind(m_hdbc, (BYTE *)&m_sd.Volume, 0, 8, 0, 0, 0, col_number++) == FAIL) return FALSE;


<...save into sql...>
BOOL CSymbolStorage::Copy(SQL_SYMBOL_DATA *sd)
{
    if(!m_bUseDB)
        return TRUE;

    memcpy(&m_sd, sd, sizeof(SQL_SYMBOL_DATA));

    if(bcp_sendrow(m_hdbc) != SUCCEED)
        return FALSE;

    return TRUE;
}
于 2012-10-27T18:40:22.847 に答える
0

水平パーティショニングを使用できますか? 参照: http://msdn.microsoft.com/en-us/library/ms178148.aspx & http://msdn.microsoft.com/en-us/library/ms188706.aspx

また、この質問を見て、復旧モデルを変更することもできます: Sql Server 2008 Tuning with large transactions (700k+ rows/transaction)

いくつかの質問: SQL Server のどのエディションを使用していますか?

1 つのコアが 80% になっているのはなぜですか? それがボトルネックである可能性があるため、おそらく調査する価値のあるものです。

使用しているOSは64ビットですか?

于 2011-01-20T13:22:19.470 に答える