假设我有一个包含a,b和c列的数据库表。我计划对所有三列进行查询,但我不确定哪些列特别是我要查询。表中有足够的行,索引极大地加快了搜索速度,但是制作可能索引的所有排列(如下所示)感觉不对:
a
b
c
a, b
a, c
b, c
a, b, c
有没有更好的方法来处理这个问题? (我很可能只是单独索引a,b,c,因为这会快速减少行数,但我想知道是否有更好的方法。)
如果您需要更具体的示例,在现实生活中的数据中,列是城市,州和邮政编码。另外,我正在使用MySQL数据库。
答案 0 :(得分:19)
在MS SQL中,索引“a,b,c”将涵盖场景“a”; “a,b”;和“a,b,c”。所以你只需要以下索引:
a, b, c
b, c
c
不确定MySQL是否以相同的方式工作,但我会这么认为。
答案 1 :(得分:4)
要在N
列上使用所有可能的相等条件的索引,您需要C([N/2], N)
个索引,即N! / ([N/2]! * (N - [N/2])!)
有关详细说明,请参阅我的博客中的这篇文章:
您还可以阅读俄语数学家Egor Timoshenko
的严格数学proof(更新:现在用英语)。
索引合并
如果列col1
,col2
和col3
具有选择性,那么此查询
SELECT *
FROM mytable
WHERE col1 = :value1
AND col2 = :value2
AND col3 = :value3
可以在col1
,col2
和col3
上使用三个单独的索引,分别选择与每个条件匹配的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
。
对于128M
行的表,这样的索引只能占用1G
临时存储空间。
以下查询:
SELECT *
FROM mytable
WHERE col1 = :value1
AND col2 = :value2
AND col3 = :value3
首先会分配一个足够大的零填充位图,以覆盖表格中所有可能的tid
(足够大,可以将所有tid
从(0, 0)
带到最后一次,不考虑遗失tid
。)
然后它将寻找第一个索引,如果满足第一个条件,则将位设置为1
。
然后它将使用AND
扫描第二个索引,1
'满足第二个条件的位。这将使1
仅用于满足两个条件的那些位。
第三个索引相同。
最后,它只会选择tid
对应于设置位的行。
tid
将按顺序提取,因此非常有效。
答案 2 :(得分: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上有索引,如果你觉得你的工作量包含更多的多列查询,那么你可以切换到多列索引。
欢呼声
答案 3 :(得分:1)
鉴于您的列实际上是城市,州和邮政编码,我建议只使用以下索引:
<强> INDEX(邮编)强>
如果我是正确的,那么邮政编码在美国并不重复,因此向索引添加城市或州信息毫无意义,因为它们对于所有邮政编码都是相同的值。例如,90210总是洛杉矶,加利福尼亚州。
INDEX(City(5))或 INDEX(City(5)),State)
这只是城市名称前五个字母的索引。在许多情况下,这将足够具体,使State
索引不会提供任何有用的过滤。例如,'Los A'几乎肯定会是来自加利福尼亚州洛杉矶的记录。也许在美国还有另一个以“洛杉矶A”开头的小镇,但是会有这么少的记录,不值得用状态数据来混淆索引。另一方面,一些城市名称出现在许多州(想到斯普林菲尔德),因此在这些情况下,最好还要将州编入索引。您需要自己弄清楚哪个索引最适合您的数据集。如果有疑问,我会选择第二个指数(城市和州)。
INDEX(州, sort_field )
州是一个非常广泛的索引(很可能只有NY和CA将拥有30%的记录)。如果您计划向用户显示此信息,例如,一次显示30条记录,那么您的查询将以
结尾... WHERE STATE = "NY"
ORDER BY <sort_field>
LIMIT <number>, 30
要使 查询有效,您需要在State索引中包含排序列。因此,如果您显示按姓氏排序的页面(假设您有该列),那么您将使用 INDEX(State,LastName(3)),否则MySQL必须排序所有< / strong>之前的'NY'记录可以为您提供所需的30个。
答案 4 :(得分:1)
这取决于你的sql-query。
指数(a,b,c)与指数(b,c,a)或指数(a,c,b)不同强>