2016-08-24 139 views
1

SQLiteデータベースから読み込むために動的に構築されたクエリを使用する複雑なC#プログラムがあります。フィールドがテーブルの主キーである場合のSQLite "MyTable(ID)の自動インデックス"

SQLite warning (284): automatic index on MyTable(Id) 

私はMyTableというのスキーマを見てきた、とIdは、主キーとして指定され、このような:

私は、デバッガの下でプログラムを実行すると、私は気づく は、私のような出力の多くを得ます
CREATE TABLE MyTable (Id varchar(50) collate nocase primary key not null, 
Name varchar(50) not null, 
(etc) 

私はSQLiteが主キーのインデックスを作ったと思っていました。それで、別のものを作るのはなぜですか?

また、関連するノートでは、サブクエリに関する自動インデックス警告が多数表示されます。たとえば、クエリに:

MyTable has Id as the primary key 
Organisations has Id as the primary key 
SubTable has a unique index on ArrangementId, OrganisationId 

は、クエリの利回りにクエリプランをEXPLAIN

SELECT MyTable.Id, MyTable.Name, Amount 
FROM MyTable 
LEFT JOIN (SELECT ArrangementId, Amount, AgreementDate FROM SubTable 
JOIN Organisations ON Organisations.Id = SubTable.OrganisationId AND Organisations.Direction = 1 
) AS MyJoin ON MyJoin.ArrangementId = MyTable.Id 
ORDER BY Id 

1|0|0|SCAN TABLE SubTable 
1|1|1|SEARCH TABLE Organisations USING INDEX sqlite_autoindex_Organisations_1 (Id=?) 
0|0|0|SCAN TABLE Arrangements USING INDEX sqlite_autoindex_Arrangements_1 
0|1|1|SEARCH SUBQUERY 1 AS MyJoin USING AUTOMATIC COVERING INDEX (ArrangementId=?) 

私はSQLiteのサブクエリということを理解してくれないと思います一時テーブルに入る必要はありませんか?

サブクエリが回避されるようにクエリを書き直す方法はありますか?

+0

、なぜあなたが使用しているvarchar型?これにより、列の値が2回、bツリーに1回、テーブルに1回格納されます。私は整数の主キーを使用し、別の列にテキストを格納することをお勧めします。必要に応じて、他の列に対しても一意制約を設定できます。 – seairth

+0

テキストにユニークなインデックスを作成すると、テキストをプライマリキーとして使用するよりもスペースが少なくなりますか? –

+0

いいえ、いずれの場合も、テキストのコピーを含むb-treeで終わります。私は、主キーとしてvarcharを使用することをより心配していました。答えでこのコメントを続ける... – seairth

答えて

1

collate nocase列の結果はcollate nocaseとなります。ルックアップで同じ照合順序を使用しない場合、そのインデックスは使用できません。 (この列との比較ではデフォルトでnocaseが使用されますが、照合順序が異なる別の列との照合が異なる場合は役に立ちません)

この照会が重要な場合は、正しい照合順序で2番目の索引を作成することを検討してください。2番目のクエリで


それは左外側の右のオペランドが参加しているため、データベースrule 3)一時テーブルを使用してサブクエリを評価しなければなりません。

あなたは、単純な一連の問合せをリライトしようとすることができますが、意味は同じままことを確信している場合は、参加する:あなたの主キーに

好奇心のうち
FROM MyTable 
LEFT JOIN SubTable ON MyTable.Id = SubTable.ArrangementId 
LEFT JOIN Organisations ON Organisations.Id = SubTable.OrganisationId 
         AND Organisations.Direction = 1 
+0

ありがとうございます。それは賢明な答えと思われます。 SubTable.OrganisationIdで同じ照合順序を設定する必要があります。さらに、クエリの簡素化も優れているようです。 –

0

次の変更を作ってみましょう:

  • メイクID整数プライマリキー。これは、実際には内部のROWIDの別名であり、別の列ではありません。
  • 現在のID(varchar列)を別の列にします。必要に応じて、一意制約を追加します(重要な場合)。
  • 子テーブルでは、varcharカラムではなく整数IDを使用します。さらに、列に外部キーを追加します。

いくつかの注意事項:

  • MyTableでINTEGER PRIMARYキーを使用して一意制約を持つ別の列にvarchar型の移動はMyTableの大きさに違いはありません。上で述べたように、主キー列は内部のROWID列の別名になるため、実際には新しい列を追加するわけではありません。
  • 外部キーとして整数を使用するように子テーブルを切り替えることで、テーブルが小さくなります。外部キー制約を追加しても、データベースは現在のサイズより小さくなります。これはまた、あなたの結合をより速くするはずです(とにかく大きなデータセットの場合)。
+0

varcharキーフィールドは実際には4文字を超えていないので、スペース節約は私の特定のケースでは最小限であると思われます。そして、Subtable.ArrangementIdを選択する他のクエリの複雑さは複雑になります(アレンジメントにジョインを追加する必要があります)。だから私はこの答えを受け入れないだろう。 –

関連する問題