6

ローカルの SQLite データベースがあります

テーブルの詳細

-- Describe PREFIX_LIST
CREATE TABLE PREFIX_LIST(ITEM VARCHAR(25) PRIMARY KEY)

-- Describe SUFFIX_LIST
CREATE TABLE SUFFIX_LIST(ITEM VARCHAR(25) PRIMARY KEY)

-- Describe VALID_LIST
CREATE TABLE VALID_LIST (
    "PART1" TEXT,
    "PART2" TEXT,
    PRIMARY KEY(PART1, PART2)
)

このリストは非常に巨大で、そこからデータを保存する必要があります。

これが私の実装です。

SQLiteConnection con = null;
SQLiteCommand cmd = null;
Connect(DbPath, ref con, ref cmd);

cmd.CommandText =
    "SELECT PART1 || '@' || PART2 FROM VALID_LIST 
 WHERE NOT EXISTS 
   (SELECT * FROM PREFIX_LIST WHERE VALID_LIST.PART1 LIKE '%' || ITEM || '%') 
   AND NOT EXISTS
   (SELECT * FROM SUFFIX_LIST WHERE VALID_LIST.PART2 LIKE '%' || ITEM || '%')";

var reader = cmd.ExecuteReader();

if (reader.HasRows)
{
    string savePath;

    if (SaveTextFile(out savePath) == DialogResult.OK)
    {
        TextWriter writer = new StreamWriter(savePath);
        while (reader.Read())
        {
            writer.WriteLine(reader.GetString(0));
        }
        writer.Close();
        writer.Dispose();
    }

}

reader.Close();
reader.Dispose();
cmd.Dispose();
con.Close();
con.Dispose();

MessageBox.Show("List Saved!.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);

リストをより速く保存できるより良い方法が必要です。VALID_LISTの合計エントリは2639117です

上記の SQL QUERY を保存するのに 15 分かかりました。

SQLクエリを最適化できる場合は、lmkしてください!

前もって感謝します

4

3 に答える 3

6

ワイルドカードがサフィックスに付けられていない限り、クエリLIKEは一般的に非常に遅くなります。などの述語はLIKE '%foo'、通常の文字列インデックスではインデックスを作成できません。

LIKEただし、sqlite での大量の使用を全文検索(FTS) 機能に置き換えることができます。

FTS3 および FTS4 拡張モジュールを使用すると、ユーザーは組み込みのフルテキスト インデックスを使用して特別なテーブルを作成できます (以降、「FTS テーブル」)。フルテキスト インデックスを使用すると、ユーザーは、テーブルに大きなドキュメントが多数含まれている場合でも、1 つ以上の単語 (以降、「トークン」) を含むすべての行を効率的にデータベースにクエリできます。

ユースケースのパフォーマンスに関して有望に見える例があります

CREATE VIRTUAL TABLE enrondata1 USING fts3(content TEXT);     /* FTS3 table */
CREATE TABLE enrondata2(content TEXT);                        /* Ordinary table *

SELECT count(*) FROM enrondata1 WHERE content MATCH 'linux';  /* 0.03 seconds */
SELECT count(*) FROM enrondata2 WHERE content LIKE '%linux%'; /* 22.5 seconds */
于 2012-10-03T21:05:20.877 に答える
2

全文検索の使用を検討してください。

これが機能するためには、PREFIX と SUFFIX の値をトークン化する必要があり (それらは別個の単語でなければなりません)、一致させようとしている ITEM はこれらの値のいずれかの個別のトークンでなければなりません (単語の一部や2つの単語を一緒に)。たとえば、PREFIX と SUFFIX の文字列は 'RED BLUE GREEN' または 'DOG, CAT, CAPYBARA' のようなものでなければならず、ITEM の値は RED、BLUE、GREEN、DOG、CAT、または CAPYBARA でなければなりません。

これらの条件が満たされている場合は、全文検索を有効にして、これらのテーブルを全文テーブルとして再作成し、LIKE (およびワイルドカード) を MATCH に置き換えることができます。この場合、SQLite は PREFIX または SUFFIX で見つかったすべてのトークンのインデックスを維持し、検索のその部分ははるかに高速になります。

残念ながら、SQlite で FTS を有効にするには、1 つ以上のコンパイル時フラグを設定してソース コードから製品をコンパイルする必要があります。私はこれについて経験がありません。

于 2012-10-03T21:07:41.923 に答える
0

これがあなたが望むものかどうかはわかりませんが、書き込みプロセスを高速化するのに役立ちます。データベースから読み取った文字列を文字列ビルダーで蓄積してから、ファイルに書き込んでみてください。たとえば、100k 文字列を読み取ってから、それらの 100k を一度にファイルに書き込むことができます。

    StringBuilder builder = new StringBuilder();
    int count = 0; //to limit the number of rows stored in string builder.
    while (reader.Read())
    {

        builder.AppendLine(reader.GetString(0));
        count++;

        //store every 100k or so rows at once. 
        //This number depends on how much RAM 
        //you can allocate towards storing the string of rows.
        //If you have 2GB of free RAM
        //this number can easily be 1 million but it always depends on the
        //size of each string stored in database.
        if(count == 100000) 
        {
           File.AppendAllText(path, builder.ToString()); //Append all rows to the file
           builder.Clear(); //clear the string for next 100k rows of data
           count = 0; //Clear the counter value
        }
        count++
    }

それが役に立ったかどうか教えてください。

于 2016-04-29T18:06:28.590 に答える