2010-04-13 63 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

简短的回答:是的,会有很多收获。至少只要你没有很多更新,但很可能会有开销,即使那里也不会显着。