2009-07-07 50 views
9

假设我有一个数据库表,列a,b和c。我打算对所有三列进行查询,但我不确定我查询的是哪些列。有一个在一个索引极大加快了搜索的表足够的行,但感觉不对的可能指标的所有排列(像这样):有没有更好的方法来索引多列而不是为每个排列创建一个索引?

a 
b 
c 
a, b 
a, c 
b, c 
a, b, c 

有没有更好的方式来处理这个问题? (这很可能我只是很好地索引a,b,c,因为这会很快减少行数,但是我想知道是否有更好的方法。)

如果您需要在实际数据中,更具体的例子是城市,州和邮政编码。另外,我正在使用MySQL数据库。

回答

19

在MS SQL中,索引“a,b,c”将覆盖您的场景“a”; “a,b”;和“a,b,c”。所以你只需要以下索引:

a, b, c 
b, c 
c 

不知道MySQL是否以相同的方式工作,但我会这样认为。

+7

这是正确的答案。 MySQL的工作方式相同,这种技术被称为“最左前缀”。从http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html上的MySQL手册:“如果表有多列索引,索引的任何最左边的前缀都可以使用例如,如果您在(col1,col2,col3)上有三列索引,则您在(col1),(col1,col2)和(col1,col2,col3)上具有索引搜索功能, “ – zombat 2009-07-07 03:20:32

+0

嗯,我应该知道这一点。 ;)非常棒,我会给这个镜头。 – 2009-07-07 03:28:26

+1

您可能还需要a,c,但这取决于您的查询的样子。您可能还需要单独的索引来涵盖Andriyev提到的OR情景,不确定。 – 2009-07-07 03:38:36

1

您创建的索引越多,在更新和删除操作期间您的性能就会越高。因为索引本身可能会更新。

是的,您可以使用多列索引。像

CREATE TABLE temp (
    id   INT NOT NULL, 
    a   INT NULL, 
    b   INT NULL, 
    c   INT NULL, 
    PRIMARY KEY (id), 
    INDEX ind1 (a,b,c), 
    INDEX ind2 (a,b) 
); 

某事,这类型的索引即IND1一定会帮你查询,如

SELECT * FROM temp WHERE a=2 AND b=3 AND c=4; 

同样,IND2将帮助您查询,如

SELECT * FROM temp WHERE a=2 AND b=3; 

但这些指标荣获”如果查询有点像

SELECT * FROM temp WHERE a=2 OR b=3 OR c=4; 

在这里,您需要单独的a,b和c索引。

因此,我不会同意John所说的那样,即在a,b,c上有索引,如果您觉得您的工作负载涵盖更多的多列查询,那么您可以切换到多列索引。

欢呼

1

鉴于您的列实际上是城市,州和邮编,我只想建议如下指标:

INDEX(邮编)

如果我是正确的,邮编这些代码在美国并不重复,所以向索引添加城市或州信息毫无意义,因为它们对于所有邮政编码都是相同的值。例如,90210总是洛杉矶,CA.

INDEX(市(5))INDEX(市(5)),州)

这仅仅是城市的名字的前五个字母索引。在很多情况下,这将具有足够的特征,使0123,索引不会提供任何有用的过滤。例如,'洛杉矶A'几乎肯定是来自洛杉矶的记录。也许在美国还有另一个以'洛杉矶A'开头的小镇,但是将会有这么几条记录,它不值得用国家数据混淆这个指数。另一方面,一些城市的名字出现在许多州(斯普林菲尔德想到),所以在这种情况下,最好也要将州列入索引。你需要弄清楚哪一个索引最适合你的数据集。如果有疑问,我会选择第二个指数(城市和州)。

INDEX(国家,sort_field

国家是一个非常宽泛的指数(很可能是纽约,独自CA将有记录的30%)。如果您计划显示这个信息给用户,比方说,30所记录的时间,那么你就必须在

... WHERE STATE = "NY" 
ORDER BY <sort_field> 
LIMIT <number>, 30 

结束了查询,以查询效率,你需要包括在排序列国家指数。因此,如果您显示按姓氏排序的页面(假设您有该列),那么您将使用INDEX(State,LastName(3)),否则MySQL必须对'NY'记录的所有进行排序它可以给你你想要的30。

1

这取决于你的sql查询。

指数(A,B,C)是不同于指数(B,C,A)指数(A,C,B)

4

要为所有可能的等同条件使用索引在N列,则需要C([N/2], N)指标,即N!/([N/2]! * (N - [N/2])!)

看到这篇文章在我的博客进行详细的解释:

您还可以通过俄罗斯数学家Egor Timoshenko读严格的数学proof

指数合并

如果列col1col2col3是有选择性的,那么这个查询

SELECT * 
FROM mytable 
WHERE col1 = :value1 
     AND col2 = :value2 
     AND col3 = :value3 

一个也可以,但是,使用下列技术得到较少的指标不俗的表现

可以在col1col2col3上使用三个单独的索引,选择单独匹配每一个条件,即ROWID的和他们找到它们的交集,就像:

SELECT * 
FROM (
     SELECT rowid 
     FROM mytable 
     WHERE col1 = :value1 
     INTERSECT 
     SELECT rowid 
     FROM mytable 
     WHERE col2 = :value2 
     INTERSECT 
     SELECT rowid 
     FROM mytable 
     WHERE col3 = :value3 
     ) mo 
JOIN mytable mi 
ON  mi.rowid = mo.rowid 

位图索引

PostgreSQL可以在查询过程中正确建立在内存中的临时位图索引。

位图索引是相当紧凑的连续位数组。

为数组设置的每个位都指示应该从表中选择相应的tid

对于具有1G行的表,这种索引可以采用临时存储的128M

以下查询:

SELECT * 
FROM mytable 
WHERE col1 = :value1 
     AND col2 = :value2 
     AND col3 = :value3 

将首先分配一个零填充的位图足够大以覆盖所有可能的tid'表中的S(即大到足以采取一切tid的从(0, 0)到最后tid,没有考虑到丢失tid的问题)。

然后它会寻找第一个索引,如果它们满足第一个条件,则将这些位设置为1

然后它将扫描第二个索引AND'满足第二个条件的位为1。只有那些满足这两个条件的位才会有1

第三个索引相同。

最后,它将只选择tid对应于设置的位的行。

tid的将被依次取出,所以它非常有效。

相关问题