2010-04-13 61 views
12

我有一個表的列是varchar(50)float。我需要(非常快)看起來與給定字符串關聯的浮點數。即使使用索引,這也相當緩慢。然而,我知道每個字符串都與一個整數相關聯,我在查找時知道這個整數,這樣每個字符串映射到一個唯一的整數,但是每個整數不會映射到唯一的字符串。有人可能會認爲它是一種樹狀結構。SQL索引varchar

有什麼要加入這個整數表,索引就可以了,使用查詢等獲得:

SELECT floatval FROM mytable WHERE phrase=givenstring AND assoc=givenint 

這是Postgres的,如果你不能告訴,我很少與數據庫的經驗。

回答

14

VARCHAR列上的按鍵可能非常長,從而導致每頁的記錄更少,深度也更深(B-Tree中的水平更高)。較長的索引也會增加緩存缺失率。

平均有多少個字符串映射到每個整數?

如果有比較少的,你只能在整數列創建索引,並PostgreSQL會做記錄的精細過濾:

CREATE INDEX ix_mytable_assoc ON mytable (assoc); 

SELECT floatval 
FROM mytable 
WHERE assoc = givenint 
     AND phrase = givenstring 

您也可以考慮創建的字符串哈希索引:

CREATE INDEX ix_mytable_md5 ON mytable (DECODE(MD5(phrase), 'HEX')); 

SELECT floatval 
FROM mytable 
WHERE DECODE(MD5(phrase), 'HEX') = DECODE(MD5('givenstring'), 'HEX') 
     AND phrase = givenstring -- who knows when do we get a collision? 

每個散列長度只有16字節,所以索引鍵會更短,但仍然幾乎完美地保留了選擇性。

+0

使用varchar時,索引鍵的比較也要昂貴得多,因爲它們可以識別locale。整數索引肯定會比任何其他選項快得多。 – 2010-04-14 15:00:33

+0

@Magnus:比較只應該做'log(n)'次數,所以我不會稱這個「很多」更貴,但是你是對的,它也會增加一些'CPU'循環。 – Quassnoi 2010-04-14 16:22:24

-1

通過在(phrase, assoc, floatval)上聲明一個索引,您將得到一個「覆蓋索引」,該索引允許在問題中發佈的查詢無需訪問表即可執行。假設單獨的phraseassoc是高度選擇性的(沒有多少行共享該字段的相同值),僅在該字段上創建索引應該產生幾乎相同的性能。

通常,您需要將索引數量限制爲最小的集合,以使您的頻繁查詢達到期望的性能。對於添加到表中的每個索引,您需要支付一定的磁盤空間,但更重要的是,您需要支付DBMS在表中每個INSERT上執行更多工作的代價。

+0

PostgreSQL沒有覆蓋索引,所以這個索引肯定是一個損失。 – 2010-04-14 14:58:48

+0

@Magnus:所以即使索引涵蓋了回答查詢所需的所有字段,PostgreSQL也必須訪問實際的表來檢索值。你有這方面的參考嗎?我有點想知道*爲什麼* :) – 2010-04-14 15:20:40

+0

從9.2開始,PostgreSQL現在只有索引掃描:https://wiki.postgresql.org/wiki/Index-only_scans#Covering_indexes該帖子頂部的詳細信息爲什麼以前沒有:使用PostgreSQL索引,「不能直接確定任何給定的元組是否對當前事務可見」。 – jwadsack 2016-01-22 18:17:32

-1

嘗試添加int並在int,varchar和include float上創建索引並不會造成傷害 - 這將會覆蓋並且非常高效 - 不確定Postgres是否包含列 - 如果它不是簡單地添加它到索引本身。

有你可以看看其他幾個技術(我不熟悉所有Postgres的功能,所以我會通過SQL Server名稱給他們):

索引視圖 - 可以有效地物化視圖,其連接幾個表 - 所以你可以加入你的varchar到你的int並且在int和varchar和float上有你的索引

包含的列 - 你可以在索引中包含列以確保索引覆蓋 - 即有索引varchar include(float) - 如果索引未覆蓋,查詢優化器仍然需要使用索引,然後執行書籤查找以獲取剩餘數據。

+1

'PostgreSQL'不支持索引視圖或包含列,但它確實支持基於函數的索引(您不必實現將表達式索引)。 – Quassnoi 2010-04-13 19:21:03

3

我只是推薦一個散列索引:

create index mytable_phrase_idx on mytable using hash(phrase); 

這種方式查詢,如

select floatval from mytable where phrase='foo bar'; 

會非常快。測試:

create temporary table test (k varchar(50), v float); 
insert into test (k, v) select 'foo bar number '||generate_series(1,1000000), 1; 
create index test_k_idx on test using hash (k); 
analyze test; 
explain analyze select v from test where k='foo bar number 634652'; 
 
                QUERY PLAN              
----------------------------------------------------------------------------------------------------------------- 
Index Scan using test_k_idx on test (cost=0.00..8.45 rows=1 width=8) (actual time=0.201..0.206 rows=1 loops=1) 
    Index Cond: ((k)::text = 'foo bar number 634652'::text) 
Total runtime: 0.265 ms 
(3 rows) 
+1

在這個測試表中,我看不到btree和hash之間的區別。 – hiroshi 2012-07-11 12:31:40

0

簡短的回答:是的,會有很多收穫。至少只要你沒有很多更新,但很可能會有開銷,即使那裏也不會顯着。