2013-03-06 58 views
0

Sqlite有一個限制,它將只使用每個查詢一個索引。目前這個限制讓我感到困擾,但我需要Sqlite,因爲我不知道任何其他可以競爭插入速度的本地數據庫引擎(儘管我願意接受建議)。必須有一些索引方案,使其工作

我有這個簡單的表(等等)一百萬上千萬行:

CREATE TABLE [Events] (
    [Id] INTEGER PRIMARY KEY, 
    [TelemetryId] INTEGER NOT NULL, 
    [TimestampTicks] INTEGER NOT NULL, 
    [Value] TEXT NOT NULL) 

看着我的數據我有大約2000獨特TelemetryId值和每個獨特TelemetryId約25000行。我一直在使用這個指數:

CREATE INDEX [IX_Events_TimestampTicks_TelemetryId] 
    ON [Events] ([TimestampTicks], [TelemetryId]) 

然而,指數未能我對我的查詢在這裏我就不在TimestampTicks約束(顯然)通過。那個索引是我在TimestampTicks和TelemetryId上嘗試過單個索引之後。在我的測試中,甚至在運行ANALYZE之後,Sqlite只會在被引用時使用TelemetryId上的索引 - 在限制爲Timestamp範圍的查詢中這是錯誤的。如果我顛倒組合索引中列的順序,那麼以前快速查詢的速度變慢。

這是我的查詢的完整列表。你能看到一個適用於所有人的索引方案嗎?

INSERT INTO Events (TelemetryId, TimestampTicks, Value) 
    VALUES(@TelemetryId, @TimestampTicks, @Value); SELECT last_insert_rowid() 

SELECT * FROM Events e 
    INNER JOIN Telemetry ss ON ss.Id = e.TelemetryId 
    INNER JOIN Services s ON s.Id = ss.ServiceId 
    WHERE s.AssetId = @AssetId AND e.TimestampTicks >= @StartTime 
    ORDER BY e.TimestampTicks LIMIT 10000 

SELECT * FROM Events e 
    WHERE e.TimestampTicks >= @StartTime 
    ORDER BY e.TimestampTicks LIMIT 10000 

SELECT * FROM Events 
    WHERE TelemetryId = @TelemetryId AND TimestampTicks <= @TimestampTicks 
    ORDER BY TimestampTicks DESC LIMIT 1 

SELECT MIN(TimestampTicks) FROM Events 
SELECT MAX(TimestampTicks) FROM Events 
SELECT COUNT(*) FROM Events 

SELECT TimestampTicks, [Value] FROM Events 
    WHERE TelemetryId = @TelemetryId 

SELECT Id FROM Events 
    WHERE TelemetryId = @TelemetryId LIMIT 2 

SELECT MIN(e.TimestampTicks) FROM Events e 
    INNER JOIN Telemetry ss ON ss.ID = e.TelemetryID 
    INNER JOIN Services s ON s.ID = ss.ServiceID 
    WHERE s.AssetID = @AssetId 

SELECT MAX(e.TimestampTicks) FROM Events e 
    INNER JOIN Telemetry ss ON ss.ID = e.TelemetryID 
    INNER JOIN Services s ON s.ID = ss.ServiceID 
    WHERE s.AssetID = @AssetId 

SELECT * FROM Events 
    WHERE TimestampTicks <= @TimestampTicks AND TelemetryId = @TelemetryId 
    ORDER BY TimestampTicks DESC LIMIT 1 

SELECT e.Id, e.TelemetryId, e.TimestampTicks, e.Value 
    FROM (SELECT e2.Id AS [Id], MIN(e2.TimestampTicks) as [TimestampTicks] 
     FROM Events e2 WHERE e2.TimestampTicks 
      BETWEEN @Min AND @Max AND e2.TelemetryId in @TelemetryIds           
      GROUP BY e2.TelemetryId) AS grp 
    INNER JOIN Events e ON grp.Id = e.Id 
+2

我會建議AssetID,TelemetryID和TimeStampTicks上的簡單非複合索引。 – Tim 2013-03-06 22:08:20

回答

1

沒有人會阻止您創建多個索引 - 每個索引都可以幫助執行某些查詢。

如果我是你,我會創造至少以下兩個指標:

CREATE INDEX events_1_ix ON Events(TimestampTicks,TelemetryId); 

(一個你一直在使用),並

CREATE INDEX events_2_ix ON Events(TelemetryId); 

的SQLite可以使用這些指標以下情況:

  1. 搜索時提供TimestampTicksTelemetryId(第一個索引)
  2. 搜索時TimestampTicks僅提供(也是第一個指數)
  3. 搜索時TelemetryId僅提供(第二索引)

如果你只創建TimestampTicksTelemetryId單獨的索引,將繼續選擇2和3快,但選項1將變得不可用。

您可以根據需要創建任意數量的索引,但要記住索引維護不是免費的。首先,它會佔用更多的磁盤空間 - 索引佔據表大小的10%-30%並不罕見。所以,如果你創建了太多的索引,它們的總大小可能會超過可用的表大小。而且,當索引很多時,插入或更新速度可能會比沒有索引時慢得多。

關於您原來的聲明,SQLite只能使用每個查詢一個索引 - 這是不正確的。

正確的說法是SQLite只能在給定的查詢中每個表使用一個索引。如果您的SQL加入多個表,則每個表都可以使用提供最佳性能的索引來訪問該表。

相關問題