我总是了解到并理解,只有当我们对前导(或所有)列有谓词时才能使用索引。现在,令我惊讶的是,我注意到以下查询中使用了GiST 索引。这是为什么?这是 GiST 索引的特殊功能吗?
CREATE TABLE t1 (
i INT,
j INT,
k INT
);
INSERT INTO t1
SELECT i, j, k
FROM GENERATE_SERIES(1, 100) AS i,
GENERATE_SERIES(1, 100) AS j,
GENERATE_SERIES(1, 100) AS k;
CREATE INDEX ON t1 USING GiST(i, j, k);
EXPLAIN SELECT * FROM t1 WHERE k = 54;
Run Code Online (Sandbox Code Playgroud)
QUERY PLAN
Bitmap Heap Scan on t1 (cost=199.03..5780.51 rows=5000 width=12)
Recheck Cond: (k = 54)
-> Bitmap Index Scan on t1_i_j_k_idx (cost=0.00..197.78 rows=5000 width=0)
Index Cond: …Run Code Online (Sandbox Code Playgroud) 我有一个 PostgreSQL 表,其中有两列名为col1and col2,都是整数类型(表中有大约 10M 行)。我想执行 SQL 查询,例如:
SELECT * FROM table WHERE col1 >= val1 AND col2 <= val2;
Run Code Online (Sandbox Code Playgroud)
(对某些val1和val2我知道的查询时间)。
如果我将 btree 索引放在上面col1并且col2PostgreSQL 尝试执行查询,在两列之一上执行索引扫描,然后在另一列上进行过滤。这意味着在大多数情况下,它必须扫过大约一半的表,即使匹配的行数很少。添加多列索引是没有用的,因为只有当两列中的至少一列经过相等性测试时,PostgreSQL 才能有效地使用它。
不过,我可以对这些值做出的一个重要假设是,这两列相对于另一列是单调的。这意味着如果在一行col1中大于或等于col1另一行中的两个,则两个对应col2条目之间的相同关系是有效的。
这意味着原则上可以通过对两列之一执行索引扫描、过滤另一列并在第二列上发现不匹配的值时立即停止执行来加快查询执行速度。在这种情况下,查询将准确读取要返回的行。
有什么方法可以在 PostgreSQL 中设置索引或任何其他不变量,以便查询规划器能够检测到这一点?
(当然,问题可以通过执行两个查询轻松解决,第一个将不等式col2转换为不等式 on col1;我问是否有办法避免这种解决方法并让 PostgreSQL 自己管理混乱)
目前,我有一个定义如下的视图:
View "public.customer_list"
Column | Type | Modifiers | Storage | Description
-----------+-------------------------+-----------+----------+-------------
id | bigint | | plain |
name | character varying(100) | | extended |
street | character varying(100) | | extended |
zip | character varying(10) | | extended |
city | character varying(100) | | extended |
country | character varying(3) | | extended |
phone | character varying(100) | | extended |
mail | character varying(100) | | extended |
rating | integer | …Run Code Online (Sandbox Code Playgroud) SELECT something FROM table WHERE primary_key = ?
Run Code Online (Sandbox Code Playgroud)
对比
SELECT something FROM table WHERE primary_key = ? AND other_key = ?
Run Code Online (Sandbox Code Playgroud)
假设这是一个包含other_key不会改变结果集的场景。在实践中第二个查询更快吗?或者,如果提供了多个,数据库是否只使用一个最佳密钥?
我有一个包含三个整数列id和a的表b。
我想获取所有记录,其中a或b匹配指定参数排序id:
select id, a, b from t where a=x or b=x order by id
Run Code Online (Sandbox Code Playgroud)
请注意,和 的x值相同。ab
这里最合适的索引是什么?
更新:我们总是在列和中寻找相同的值,这一事实有什么用处吗?我们可以为此创建一个表达式索引吗?ab
通常,支持多列 B 树索引的 SQL 数据库还支持按索引中列的子集进行查找,当且仅当它们是索引中的第一列。例如,如果我在列上有一个索引(a, b, c, d)并想执行:
SELECT * FROM my_table
WHERE b = 7 AND a = 'foo';
Run Code Online (Sandbox Code Playgroud)
然后这将使用索引并且速度很快,因为该对(a, b)位于索引的开头,因此数据库可以导航树以查找以('foo', 7, ... ).开头的索引记录。但是,如果我跑
SELECT * FROM my_table
WHERE b = 7 AND c = 'bar';
Run Code Online (Sandbox Code Playgroud)
那么索引将不会被使用*,因为匹配的记录将根据它们在 column 中的值分布在整个索引中a。
* (除了可能通过对索引进行完整或部分扫描,如下面Evan 的回答中所述 - 但由于完整索引扫描仍然具有与完整表扫描相同的时间复杂度,并且部分索引扫描可能也会这样做,这没有多大帮助。)
我有一个包含n列和潜在大量行的表。我还有一个前端 GUI,它允许用户通过这些列的任意组合的精确值进行过滤并查看结果表。这个前端产生的任何查询导致全表扫描得到结果是不可接受的;每个可能的过滤器都必须由索引支持。
对于n列,我需要创建的 B 树索引的最小数量是多少,以确保某个索引覆盖了所有可能的列组合?
假设我的表有4列:a,b,c,和d …
MySQL不能在WHERE条件不包括构成最左边前缀的列的查找中使用复合索引:
如果列不构成索引的最左边前缀,MySQL 不能使用索引来执行查找。
来自这个关于 PostgreSQL 的回答的引述引起了我的注意:
这在 Oracle 11 中有些不同,它有时也可以使用不在索引定义开头的列。
在什么情况下 Oracle(至少在 11g 中)可以在查询中不存在最左侧前缀列的情况下进行查找?
我需要搜索一个非常大的PostgreSQL表(500+M行),我想限制返回的搜索结果,但是使用“limit”关键字并不能阻止对整组数据的搜索(正确吗?)
想象一下我的搜索结果包含 1M 行,但我只需要搜索结果中的前 100 条记录!PostgreSQL 数据库是否必须在内存中临时创建这 1M 搜索结果行,然后给我所需的 100 个结果?
或者有什么办法告诉PostgreSQL一旦找到100条记录就停止搜索?
这是我的表,当然还没有填充 500M 记录!
CREATE TABLE con
(
id bigserial NOT NULL,
tag1 integer NOT NULL DEFAULT 0,
tag2 integer NOT NULL DEFAULT 0,
ref1 integer NOT NULL DEFAULT 0,
ref2 integer NOT NULL DEFAULT 0,
CONSTRAINT con_pkey PRIMARY KEY (id)
)
Run Code Online (Sandbox Code Playgroud)
以及测试查询的解释分析:
explain analyze SELECT * FROM con where tag1 = '64813' and tag2 = '80'
Run Code Online (Sandbox Code Playgroud)
Seq Scan on con (cost=0.00..3215204.72 rows=2470 width=112) (actual time=0.016..36970.528 rows=7505 loops=1)
Filter: …Run Code Online (Sandbox Code Playgroud) 我正在管理一个包含几百万条记录的表,这些记录被实时插入。我的应用程序的一部分需要显示最后插入的 N 行,所以一开始我只是查询:
select id, logdate, content from measurements order by logdate DESC limit 500;
Run Code Online (Sandbox Code Playgroud)
几天后,我发现设置id为(对于此示例)更快10000000000 - extract(epoch from logdate),并将其用作PRIMARY KEY,所以
select id, date, content from measurements limit 500;
Run Code Online (Sandbox Code Playgroud)
自然会按 排序id,因此会产生最新的记录。
随着表的增长,它变得难以管理,所以我求助于分区。我按照文档说的那样做了:
CREATE TABLE measurement_y2007m11 (
CHECK ( logdate >= DATE '2007-11-01' AND logdate < DATE '2007-12-01' )
) INHERITS (measurement);
CREATE TABLE measurement_y2007m12 (
CHECK ( logdate >= DATE '2007-12-01' AND logdate < DATE '2008-01-01' )
) INHERITS (measurement); …Run Code Online (Sandbox Code Playgroud) postgresql ×7
performance ×6
index ×5
btree ×1
gist-index ×1
index-tuning ×1
optimization ×1
oracle ×1
partitioning ×1