sql - 一个表可以拥有的最大有用索引数?
问题描述
会议
在上周的一次会议上,客户正在讨论如何更快地制作重要的搜索页面。该页面通过询问任何字段的值(字符串)来搜索单个表(12 列,2000 万行);它返回 50 行(分页),从指定的条件开始(每列可以升序或降序)。当条件与现有索引不匹配时,搜索会变慢,客户端会不高兴。
然后——在会议进行到一半——半技术分析师把这个抛到了空中:为什么我们不在桌子上创建所有可能的索引来让一切都快呢?
我立即回答“不,太多了,修改表会很慢,所以我们需要创建一些巧妙选择的索引来做到这一点”。我们最终创建了最有用的页面,页面现在更快了。问题解决了。
问题
但仍然......我一直在思考这个问题,我想更好地理解它,所以这里是:
理论上,我可以在具有 N 列的表上创建多少个可能的有用索引?
我认为通过有用我们应该考虑(我可能是错的):
- 其他索引尚未涵盖的索引:例如,如果包含 (a, b, c),则不应计算 (a, b)。
- 为了显示多行(不仅仅是相等),当升序和降序索引是复合索引的一部分时,它们应该被计为单独的索引。即: (a) 与 (a DESC) 的目的相同,但 (a, b) 与 (a DESC, b) 的目的不同。
因此,具有单列 (a) 的表只能有一个索引:
(a)
使用两列 (a, b) 我可以有四个有用的索引:
(a, b)
(b, a)
(a DESC, b)
(b DESC, a)
(a) -- already covered by #1
(b) -- already covered by #2
(a, b DESC) -- already coverred by #1 (reading index in reverse)
(b, a DESC) -- already covered by #2
(a DESC, b DESC) -- already covered by #3
(b DESC, a DESC) -- already covered by #4
(a DESC) -- already covered by #3
(b DESC) -- already covered by #4
三列(a,b,c):
(a, b, c)
(a, c, b)
(b, c, a)
(b, a, c)
(c, a, b)
(c, b, a)
...
解决方案
所有其他答案都包含一些有价值的东西,但是我不得不说的足够多,以保证第三个答案。
像你说的那样,这个问题没有确切的答案。在某种程度上,这就像问“你认为一个人疯了的极限是多少?” 有很大的灰色地带。
我的观点是:
如果添加太多索引会发生什么:
修改表变得非常慢。即使索引很少,数据操作也会变得慢一个数量级。如果您想要
INSERT
,UPDATE
或者DELETE
,具有所有可以想象的索引的表会使这样的操作非常缓慢。对于许多索引,查询规划器必须考虑许多不同的访问路径,因此添加任何索引都会使查询规划变得稍微慢一些。对于非常多的索引,甚至在执行程序开始工作之前,计划开销很可能会使查询变得太慢。
您可以做些什么来减少所需的索引数量:
看看运营商。如果从不使用运算符
<
、和<=
,则添加具有降序列的索引是没有意义的。>=
>
请记住,索引 on
(a, b, c)
也可用于仅a
在其条件中使用的查询,因此您不需要额外的索引 on(a)
。
对您来说,可行的前进方向是什么?
我有两个建议:
一种方法是在十二列中的每一列上添加一个简单的索引。
十二个指数已经不少了,但你还没有在疯狂的范围内。
PostgreSQL 可以在具有多个列的条件的查询中有效地使用这些索引,即使单独的条件都没有足够的选择性来保证索引扫描。
这是因为 PostgreSQL 有位图索引扫描。请参阅文档中的此示例:
EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000; QUERY PLAN ------------------------------------------------------------------------------------- Bitmap Heap Scan on tenk1 (cost=25.08..60.21 rows=10 width=244) Recheck Cond: ((unique1 < 100) AND (unique2 > 9000)) -> BitmapAnd (cost=25.08..25.08 rows=10 width=0) -> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0) Index Cond: (unique1 < 100) -> Bitmap Index Scan on tenk1_unique2 (cost=0.00..19.78 rows=999 width=0) Index Cond: (unique2 > 9000)
扫描每个索引并形成一个位图,其中包含匹配条件的每一行的 1。然后组合位图,最后从表中取出行。
另一个想法是使用布隆过滤器。
如果您的条件中唯一的运算符是
=
,您可以CREATE EXTENSION bloom;
并在所有表列上创建一个索引
USING bloom
。这样的索引可用于在子句中具有任意列组合的查询。
WHERE
不利的一面是它是一个有损索引,因此您会得到必须提取和过滤掉的误报结果。这取决于您的情况,但这可能是一个优雅的(并且被低估了!)解决方案,可以平衡查询和更新速度。
推荐阅读
- apache-kafka - fetch.max.message.bytes 和 max.message.bytes Kafka 配置
- reactjs - 无法使用 FlatList 上的简单映射对未安装的组件执行 React 状态更新
- html - Ruby on rails send_data/send_file 在点击多条记录时仅下载最新文件
- c++ - Dijkstra 算法需要什么样的图表?C++
- javascript - 如何在值之间用逗号推送数组
- c - 带有 argp.h 的帮助消息中的文本间距错误
- php - 如何过滤属于特定类别的帖子 [产品]
- google-chrome - 从扩展打开背景选项卡
- python - 使用 Tweepy 时如何删除 Twitter 帖子的链接?
- python - 如何将列值与另一个数据框中的行值匹配,每行有多个值?