pg9.6使用索引
使用索引
索引是用于快速数据检索操作的结构。在数据库世界中,索引与表相关联并用于有效定位数据,而无需查询数据库表中的每一行。如果表没有索引,则需要全表扫描才能找到记录,这在磁盘 I/O 和 CPU 利用率方面非常昂贵。全表扫描是从磁盘顺序读取每条记录、检查搜索条件并构建结果集的过程。
在本文中,您将学习以下主题:
- 什么是索引
- 如何创建索引
- 索引有哪些不同类型
- 如何使用不同的索引方法
- 索引问题
什么是索引
索引以额外的数据副本为代价来改进数据库操作的性能。由于索引存储额外的数据副本以加快访问速度,因此索引是改进数据库性能的常规方法。简而言之,索引是对数据库中表的单行的快速访问路径。数据库索引类似于书籍索引,任何特定信息都可以通过查看索引页来定位,以避免对书籍进行全面搜索,这是一种穷举操作。类似地,创建数据库索引以最小化表遍历并最大化性能。
可以使用表的单列或多列创建索引。一旦创建了索引,就不需要进一步的干预;索引将在表上的每个 DML 操作上自动更新。创建索引后,规划器根据成本决定使用索引代替顺序扫描。
当 PostgreSQL 执行一个查询时,它必须选择一个执行策略。规划器是负责建立执行有效搜索的最佳策略的软件。
假设我们有一个名为item的表,其中包含item_id、 item_name、 item_price和item_data列,并且包含数百万行。让我们通过psql命令行实用程序连接到warehouse_db数据库,并按以下方式创建项目表:
db1=# CREATE TABLE item
(
item_id INTEGER NOT NULL,
item_name TEXT,
item_price NUMERIC,
item_data TEXT
);
可以使用以下语句查看结果:
db1=# SELECT item_name FROM item WHERE item_id = 100;
如果我们想通过前面的查询得到一个特定商品的详细信息,那么就需要扫描整个表来找到item_id为100的商品,这是一个严重的性能问题。这个问题可以使用索引来解决。
EXPLAIN QUERY命令可用于检查将用于查询的扫描。
这可以用下面的例子来解释:
db1=# EXPLAIN SELECT * FROM item;
QUERY PLAN
---------------------------------------------------------
Seq Scan on item (cost=0.00..16.30 rows=630 width=100)
(1 row)
如何创建索引
CREATE INDEX命令用于创建索引;在表上创建索引的基本语法如下:
CREATE INDEX index_name ON table_name (column_name);
下面是在item表的item_id列上创建索引的示例:
db1=# CREATE INDEX item_idx ON item (item_id);
CREATE INDEX
可以使用以下语句查看结果:
db1=# \di item_idx
List of relations
Schema | Name | Type | Owner | Table
--------+----------+-------+----------+-------
public | item_idx | index | postgres | item
(1 row)
索引名称是可选的;如果未指定索引名,PostgreSQL 将使用表名和列名生成索引名。在前面的示例中,我们指定了索引名称。在以下示例中,PostgreSQL 使用表名和列名生成索引名称,即item_item_id_idx:
db1=# CREATE INDEX ON item (item_id);
CREATE INDEX
可以使用以下语句查看结果:
db1=# \di item_item_id_idx
List of relations
Schema | Name | Type | Owner | Table
--------+------------------+-------+----------+-------
public | item_item_id_idx | index | postgres | item
(1 row)
在大表上创建索引可能需要很长时间;例如,在前面的示例中,查询必须扫描所有记录并生成索引数据。
索引需要额外的磁盘空间,因此在创建索引时要小心。此外,insert/delete/update 需要更多的处理来维护索引数据,索引的类型对性能有不同的影响。例如,B 树索引需要树重新平衡,这在计算成本方面非常繁重。
下面是创建索引的完整语法:
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON table_name [ USING method ]
( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
[ WITH ( storage_parameter [= value] [, ... ] ) ]
[ TABLESPACE tablespace_name ]
[ WHERE predicate ]
有关创建索引的完整语法的详细信息,请访问以下链接在线提供的官方 PostgreSQL 文档:
https://www.postgresql.org/docs/9.6/sql-createindex.html
如何删除索引
DROP INDEX命令用于删除现有索引。它的基本语法如下:
DROP INDEX index_name;
删除索引不会影响表的行,但要小心,因为它会影响数据库的性能。
索引类型
PostgreSQL 数据库支持单列索引、多列索引、部分索引、唯一索引、表达式索引、隐式索引和并发索引。
单列索引
当一个表主要代表一个单一类别的数据,或者查询仅围绕表中的一个类别时,使用单列索引。通常,在数据库设计中,表代表单一类别的数据,因此通常使用单列(类别)索引。它的语法如下:
CREATE INDEX index_name ON table_name (column);
看看下面的例子:
db1=# SELECT COUNT(*) FROM item WHERE item_id = 100;
count
-------
202
(1 row)
Time: 201.206 ms
在这个例子中,需要item_id为100的行。如果没有定义索引,则将扫描整个表以查找item_id为100 的行,这是一个昂贵的操作。如果仔细观察, WHERE子句中只使用了一个列,从而在单个列上创建了索引,在前面的查询中是item_id 。这优化了该查询。
现在,考虑以下示例:
db1=# CREATE INDEX item_index ON item (item_id);
可以使用以下语句查看结果:
db1=# \d item
Table "public.item"
Column | Type | Modifiers
------------+---------+-----------
item_id | integer | not null
item_name | text |
item_price | numeric |
item_data | text |
Indexes:
"item_idx" btree (item_id)
"item_index" btree (item_id)
"item_item_id_idx" btree (item_id)
现在,我们已经在表项的item_id列上创建了一个 B 树索引item_index ,所以现在我们再次尝试相同的SELECT查询,看看创建索引后需要多少时间。
在表上创建索引大大减少了SELECT查询时间,如以下输出所示:
db1=# SELECT COUNT(*) FROM item WHERE item_id = 100;
count
-------
202
(1 row)
Time: 1.140 ms
有索引和没有索引有明显的时间差异。没有索引的相同查询执行大约需要200 毫秒,而创建索引后的查询大约需要1 毫秒。
- 提示
\d table_name查询用于描述表。
\timing查询用于显示查询时间。
多列索引
在某些情况下,数据库中的表涉及多个类别的数据。在这种情况下,单列索引可能无法提供良好的性能。在这种情况下,就需要多列索引。 PostgreSQL 支持多列索引。它的语法如下:
CREATE INDEX index_name ON table_name (column1, column2);
多列索引,在一个查询中涉及多个列,有助于优化查询;让我们看一个例子。
在本例中,我们将获取item_id小于200且item_price也为100的记录总数;首先,我们在表上尝试不带索引的查询,并按以下方式记下查询时间:
db1=# SELECT COUNT(*) FROM item WHERE item_id < 200 AND item_price = 100;
count
-------
202
(1 row)
Time: 1675.783 ms
现在,我们将创建一个单列索引,按以下方式尝试相同的查询,并记下查询执行时间:
db1=# CREATE INDEX item_single_index ON item (item_id);
可以使用以下语句查看结果:
db1=# SELECT COUNT(*) FROM item WHERE item_id < 200 AND item_price = 100;
count
-------
202
(1 row)
Time: 1604.328 ms
最后,在表上创建一个多列索引,按以下方式尝试相同的查询,并记下查询的时间:
db1=# CREATE INDEX item_multi_index ON item (item_id, item_price);
可以使用以下语句查看结果:
db1=# SELECT COUNT(*) FROM item WHERE item_id < 200 AND item_price = 100;
count
-------
202
(1 row)
Time: 331.295 ms
查询时间如下:
无索引 | 单列索引 | 多列索引 |
---|---|---|
1675.783 ms | 1604.328 ms | 331.295 ms |
我们可以观察到前面查询的执行时间的差异。没有索引的查询耗时1675.783 毫秒,具有单列索引的查询运行速度稍快,耗时1604.328 毫秒,而具有多列索引的查询运行速度更快,仅耗时331.295 毫秒。因此,创建单列或多列索引取决于所用查询的性质,因此选择合适的索引可以真正提高性能。
- 提示
默认情况下,索引是按升序创建的;要按降序创建索引,请在列名后使用DESC 。
部分索引
部分索引是只适用于满足指定条件的行的索引。大多数时候,表的子集用于查询。在这种情况下,对整个表创建索引既浪费空间又耗时。在这种情况下,我们应该考虑在表的子集上创建索引。与在整个表上创建索引相比,使用部分索引的根本原因是通过使用最少的磁盘空间获得更好的性能。
要在表的子集上创建索引,我们使用部分索引。部分索引可以通过在创建索引时指定WHERE条件来创建,如下:
CREATE INDEX index_name ON table_name (column) WHERE (condition);
假设大部分查询使用item_id小于106的item表的子集,然后在整个item表上创建索引是浪费空间。最佳情况是仅在warehouse_tbl表的前 100 行上创建索引。在这种情况下,可以为小于 100 的行创建部分索引。这可以通过以下方式完成:
db1=# CREATE INDEX item_partial_index ON item (item_id) WHERE (item_id < 106);
可以使用以下语句查看结果:
CREATE INDEX
db1=# \d item
Table "public.item"
Column | Type | Modifiers
------------+---------+-----------
item_id | integer | not null
item_name | text |
item_price | numeric |
item_data | text |
Indexes:
"item_idx" btree (item_id)
"item_index" btree (item_id)
"item_item_id_idx" btree (item_id)
"item_partial_index" btree (item_id) WHERE item_id < 106
- 提示
B 树索引最多支持 32 列连接到一个索引中。
唯一索引
可以在任何列上创建唯一索引;它不仅创建索引,而且强制列的唯一性。这是数据库设计中最重要的索引,因为它确保数据完整性并提供性能增强。有多种创建唯一索引的方法:使用CREATE UNIQUE INDEX命令,通过在表上创建唯一约束,或通过创建主键。
这是由CREATE UNIQUE INDEX命令创建的唯一索引的示例:
db1=# CREATE UNIQUE INDEX item_unique_idx ON item (item_id);
CREATE INDEX
可以使用以下语句查看结果:
db1=# \d item_unique_idx
Index "public.item_unique_idx"
Column | Type | Definition
---------+---------+------------
item_id | integer | item_id
unique, btree, for table "public.item"
我们可以使用CREATE UNIQUE INDEX命令显式创建唯一索引,也可以通过在表上声明主键来隐式创建它。以下是通过在表上创建主键来隐式创建唯一索引的示例:
db1=# CREATE TABLE item
(
item_unique INTEGER PRIMARY KEY,
item_name TEXT,
item_price NUMERIC,
item_data TEXT
);
可以使用以下语句查看结果:
db1=# \d item
Table "public.item"
Column | Type | Modifiers
-------------+---------+-----------
item_unique | integer | not null
item_name | text |
item_price | numeric |
item_data | text |
Indexes:
"item_pkey" PRIMARY KEY, btree (item_unique)
以下是通过定义唯一约束隐式创建唯一索引的示例:
db1=# ALTER TABLE item ADD CONSTRAINT primary_key UNIQUE(item_unique);
前面的 SQL 语句更改了表并在item表的item_id列上添加了唯一约束,并且该语句还隐式创建了一个唯一索引(B 树)。
在这里,我们重新查看原始表:
db1=# \d item
Table "public.item"
Column | Type | Modifiers
-------------+---------+-----------
item_unique | integer | not null
item_name | text |
item_price | numeric |
item_data | text |
Indexes:
"item_pkey" PRIMARY KEY, btree (item_unique)
"primary_key" UNIQUE CONSTRAINT, btree (item_unique)
ALTER命令为item_id列添加了唯一约束,可以用作主键。
使用 CREATE 显式创建索引
我们已经讨论了如何在表上隐式创建唯一索引,但是有一种方法可以使用已经讨论过的CREATE INDEX命令显式创建唯一索引,如下所示:
db1=# CREATE TABLE item
(
item_unique INTEGER PRIMARY KEY,
item_name TEXT,
item_price NUMERIC,
item_data TEXT
);
我们使用以下语句创建唯一索引:
db1=# CREATE UNIQUE INDEX idx_unique_id ON item (item_id);
CREATE INDEX
可以使用以下语句查看结果:
db1=# \d item
Table "public.item"
Column | Type | Modifiers
------------+---------+-----------
item_id | integer | not null
item_name | text |
item_price | numeric |
item_data | text |
Indexes:
"item_pkey" PRIMARY KEY, btree (item_id)
"idx_unique_id" UNIQUE, btree (item_id)
在所有情况下,唯一索引可确保数据的完整性并在已存在的情况下抛出错误。这可以在以下示例中看到:
db1=# INSERT INTO item VALUES (1, 'boxing', 200, 'gloves');
INSERT 0 1
db1=# INSERT INTO item VALUES (1, 'hockey', 300, 'shoes');
ERROR: duplicate key value violates unique constraint "item_pkey"
DETAIL: Key (item_id)=(1) already exists.
- 提示
只有 B‑tree、GiST 和 GIN 索引支持唯一索引。
表达式索引
我们已经讨论了在表的列上创建索引,但在某些情况下,需要在表的一个或多个列上添加表达式。例如,如果我们要搜索不区分大小写的项目名称,那么正常的做法如下:
db1=# SELECT * FROM item WHERE UPPER(item_name) LIKE 'COFFEE';
前面的查询将扫描每一行或表并将item_name转换为大写并将其与COFFEE 进行比较;这真的很贵。以下是在item_name列上创建表达式索引的命令:
db1=# CREATE INDEX item_expression_index ON item(UPPER(item_name));
可以使用以下语句查看结果:
db1=# \d item
Table "public.item"
Column | Type | Modifiers
------------+---------+-----------
item_id | integer | not null
item_name | text |
item_price | numeric |
item_data | text |
Indexes:
"item_pkey" PRIMARY KEY, btree (item_id)
"idx_unique_id" UNIQUE, btree (item_id)
"item_expression_index" btree (upper(item_name))
仅当在定义中的查询中使用精确表达式时才使用表达式索引。在这个例子中,我们查询item表并没有使用表达式,所以规划器没有使用表达式索引。这可以看如下:
db1=# EXPLAIN SELECT item_name FROM item WHERE item_name = 'item-10';
QUERY PLAN
---------------------------------------------------------
Seq Scan on item (cost=0.00..22759.00 rows=1 width=11)
Filter: (item_name = 'item-10'::text)
(2 rows)
但是,在此示例中,我们使用了与索引定义中相同的表达式,因此规划器按以下方式选择该索引:
db1=# EXPLAIN SELECT item_name FROM item WHERE UPPER(item_name) = 'ITEM-10';
QUERY PLAN
-------------------------------------------------------------
Bitmap Heap Scan on item (cost=107.18..8714.04 rows=5000 width=11)
Recheck Cond: (upper(item_name) = 'ITEM-10'::text)
-> Bitmap Index Scan on item_expression_index
(cost=0.00..105.93 rows=5000 width=0)
Index Cond: (upper(item_name) = 'ITEM-10'::text)
(4 rows)
隐式索引
由数据库自动创建的索引称为隐式索引。主键或唯一约束隐式地在该列上创建索引。隐式索引已在本文前面的唯一索引部分讨论过。
并发索引
建立索引时会锁定表,使其无法在表中写入或插入任何内容。在创建过程中,可以毫无问题地读取表,但写入操作会阻塞,直到索引构建过程结束。我们已经讨论过,在表上创建索引是一项非常昂贵的操作,在相当大的表上,建立索引可能需要数小时。这可能会导致难以执行任何写入操作。为了解决这个问题,
PostgreSQL 有并发索引,当你需要为一个实时数据库中添加索引时,它很有用。
并发索引的语法如下:
CREATE INDEX CONCURRENTLY index_name ON table_name using btree(column);
- 提示
并发索引比普通索引慢,因为它分两部分完成索引构建。这可以借助以下示例进行解释:
使用CREATE INDEX创建普通索引idx_id所花费的时间:
db1=# CREATE INDEX idx_id ON item (item_id);
Time: 8265.473 ms
使用CREATE INDEX CONCURRENTLY创建并发索引idx_id所花费的时间:
db1=# CREATE INDEX CONCURRENTLY idx_id ON item (item_id);
Time: 51887.942 ms
索引类型
PostgreSQL 支持 B‑tree、hash、GiST 和 GIN 索引方法。可以通过USING方法选择索引方法或类型。不同类型的索引有不同的用途,例如,当查询涉及范围和相等运算符时有效使用B树索引,当查询中使用相等运算符时有效使用散列索引。
下面是一个如何使用索引类型的简单示例:
CREATE INDEX index_name ON table_name USING btree(column);
B树索引
当查询涉及相等运算符(=)和范围运算符(<、 <=、 >、 >=、 BETWEEN和IN)时,可以有效地使用 B 树索引。
哈希索引
当查询仅涉及简单的等效运算符时,将使用哈希索引。在这里,我们在item表上创建一个哈希索引。您可以在以下示例中看到,规划器在等效运算符的情况下选择哈希索引,而在范围运算符的情况下不使用哈希索引:
db1=# CREATE INDEX item_hash_index ON item USING HASH(item_id);
如前所述,散列索引最适合在WHERE子句中具有等效运算符的查询。这可以借助以下示例进行解释:
db1=# EXPLAIN SELECT COUNT(*) FROM item WHERE item_id = 100;
QUERY PLAN
------------------------------------------------------------------
Aggregate (cost=8.02..8.03 rows=1 width=0)
-> Index Scan using item_hash_index on item (cost=0.00..8.02 rows=1
width=0)
Index Cond: (item_id = 100)
(3 rows)
哈希索引方法不适用于范围操作符,因此规划器不会选择哈希索引进行范围查询:
db1=# EXPLAIN SELECT COUNT(*) FROM item WHERE item_id > 100;
QUERY PLAN
------------------------------------------------------------------
Aggregate (cost=25258.75..25258.76 rows=1 width=0)
-> Seq Scan on item (cost=0.00..22759.00 rows=999900 width=0)
Filter: (item_id > 100)
(3 rows)
- 提示
要获取表和索引的大小,我们可以使用以下命令:
SELECT pg_relation_size('table_name') AS table_size,pg_relation_size('index_name') index_size
FROM pg_tables WHERE table_name like 'table_name';
GiST 索引
通用搜索树(GiST)索引提供了使用索引访问方法创建自定义数据类型的可能性。它还提供了一组广泛的查询。
它可以用于等价和范围比较之外的操作。 GiST 索引是有损的,这意味着它可以创建不正确的匹配项。
GiST 索引的语法如下:
CREATE INDEX index_name ON table_name USING gist(column_name);
- 提示
使用 GiST 开发的模块和扩展有rtree_gist、 btree_gist、 intarray、 tsearch、 ltree和cube。其完整详情可在以下链接中找到:
http://www.postgresql.org/docs/9.6/static/gist-examples.html
GIN索引
可以在以下链接中找到的以下引用的帮助下引入 GIN 索引:
https://www.postgresql.org/docs/9.6/gin-intro.html
“GIN 代表广义倒排索引。 GIN 是为处理被索引的项是复合值的情况而设计的,索引要处理的查询需要搜索出现在复合项中的元素值。例如,项目可以是文档,查询可以是搜索包含特定单词的文档”
下面是创建 GIN 索引的语法:
db1=# CREATE INDEX index_name ON table_name USING gin(column_name);
- 提示
GIN 索引需要的空间是 GiST 的三倍,但速度是 GiST 的三倍。
让我们举一个例子,我们想要使用部分匹配从数百万个单词中搜索一个单词。 GIN 索引最适合这些类型的查询:
db1=# CREATE EXTENSION pg_trgm;
创建pg_trgm扩展后,我们使用以下语句创建单词表:
db1=# CREATE TABLE words(lineno INT, simple_words TEXT, special_words TEXT);
我们可以使用以下语句将数据插入到words表中:
db1=# INSERT INTO words VALUES (generate_series(1,2000000), md5(random()::TEXT), md5(random()::TEXT));
让我们尝试执行一个查询来搜索simple_words和special_words中具有a31的单词,并注意查询的执行时间如下:
db1=# SELECT count(*) FROM words WHERE simple_words LIKE '%a31%' AND special_words LIKE '%a31%';
count
-------
116
(1 row)
Time: 1081.796 ms
创建一个多列索引并尝试执行相同的查询并按以下方式记下查询的时间:
db1=# CREATE INDEX words_idx ON words (simple_words, special_words);
Time: 32822.055 ms
可以使用以下语句查看结果:
db1=# SELECT count(*) FROM words WHERE simple_words LIKE '%a31%' AND special_words LIKE '%a31%';
count
-------
116
(1 row)
Time: 1075.467 ms
现在,在表上创建一个 GIN 索引,再次执行相同的查询,并按以下方式记下时间:
db1=# CREATE INDEX words_idx ON words USING gin (simple_words gin_trgm_ops, special_words gin_trgm_ops);
CREATE INDEX
Time: 142836.712 ms
可以使用以下语句查看结果:
db1=# SELECT count(*) FROM words WHERE simple_words LIKE '%a31%' AND special_words LIKE '%a31%';
count
-------
116
(1 row)
Time: 7.105 ms
现在从下表中,我们可以清楚地看到使用GIN索引:
没有索引的时间 | 有多列索引的时间 | 有GIN索引的时间 |
---|---|---|
1081.796 ms | 1075.467 ms | 7.105 ms |
- 提示
有关 GIN 索引的更多详细信息,请访问http://www.sai.msu.su/~megera/wiki/Gin。
有关pg_trgm和gin_trgm_ops的更多详细信息,请访问http://www.postgresql.org/docs/9.6/static/pgtrgm.html。
索引膨胀
由于PostgreSQL的架构是基于MVCC的,所以表存在死行。对任何事务都不可见的行被视为死行。在连续表中,一些行被删除或更新。这些操作会导致表中出现死行。插入新数据时,可能会重复使用死行。由于死行很多,所以会出现膨胀。索引膨胀有多种原因,需要修复它才能获得更高的性能,因为它会损害数据库的性能。AUTO VACUUM是避免膨胀的最佳方法,但它是一个可配置的参数,可能会被禁用或错误配置。有多种方法可以修复索引膨胀;因此,我们将在以下部分讨论避免这种情况的方法及其功效。
要了解有关 MVCC 的更多信息,请查看http://www.postgresql.org/docs/current/static/mvcc-intro.html。
转储和恢复
在出现膨胀的情况下,最简单的预防方法是使用pg_dump备份表,删除表,并将数据重新加载到初始表中。这是一项昂贵的操作,有时似乎限制太多。
vacuum
使用VACUUM命令清空表是另一种可用于修复膨胀的解决方案。 VACUUM命令重新排列行以确保页面尽可能满,但数据库文件收缩仅在文件末尾有 100% 的空页时才会发生。这是VACUUM可用于减少膨胀的唯一情况。它的语法如下:
VACUUM table_name
以下示例显示了VACUUM在item表上的用法:
db1=# VACUUM item;
另一种使用VACUUM的方法如下:
db1=# VACUUM FULL item;
CLUSTER
正如我们之前所讨论的,重写和重新排序行可以解决可以使用转储/恢复间接实现的问题,但这是一项昂贵的操作。执行此操作的另一种方法是CLUSTER命令,它用于根据索引对行进行物理重新排序。 CLUSTER命令用于创建表的完整初始副本,并删除数据的旧副本。 CLUSTER命令需要足够的空间(实际上是磁盘空间的两倍)来保存数据的初始组织副本。它的语法如下:
CLUSTER table_name USING index_name
用于获取索引和表的大小/行的一些查询如下:
db1=# CREATE TABLE table_name AS SELECT * FROM generate_series(1,9999999) AS COLUMN_KEY;
SELECT 9999999
db1=# CREATE INDEX index_name ON table_name (column_key);
CREATE INDEX
db1=# SELECT table_len/(1024*1024) table_size, tuple_count total_rows FROM pgstattuple('table_name');
table_size | total_rows
------------+------------
345 | 9999999
(1 row)
db1=# SELECT table_len/(1024*1024) table_size, tuple_count total_rows FROM pgstattuple('index_name');
table_size | total_rows
------------+------------
214 | 9999999
(1 row)
重建索引
如果索引由于膨胀或数据变得随机分散而变得低效,则需要重建索引以从索引中获得最大性能。它的语法如下:
db1=# REINDEX TABLE item;
思考要点
使用索引时,需要注意以下几点:
- 当表中有大量行时,表列上的索引是有意义的。
- 检索数据时,您需要确保索引的良好候选者是外键和检索数据时可以使用min()和max()的键。这意味着列选择性对于有效索引非常重要。
- 不要忘记删除未使用的索引以获得更好的性能。此外,每月对所有索引执行一次REINDEX以清理死元组。
- 如果您有大量数据,请使用表分区和索引。
- 当您为具有空值的列索引时,请考虑使用WHERE column_name IS NOT NULL 的条件索引。
pg9.6使用索引的更多相关文章
- 索引范围扫描(INDEX RANGE SCAN)
索引范围扫描(INDEX RANGE SCAN)适用于所有类型的B树索引,当扫描的对象是唯一性索引时,此时目标SQL的where条件一定是范围查询(谓词条件为 BETWEEN.<.>等): ...
- postgresql----Btree索引
当表数据量越来越大时查询速度会下降,像课本目录一样,在表的条件字段上创建索引,查询时能够快速定位感兴趣的数据所在的位置.索引的好处主要有加速带条件的查询,删除,更新,加速JOIN操作,加速外键约束更新 ...
- PostgreSQL 索引膨胀
索引膨胀,主要针对B-tree而言 索引膨胀的几个来源: 大量删除发生后,导致索引页面稀疏,降低了索引的使用效率: PG9.0之前的版本,vacuum full会同样导致索引页面稀疏: 长时间运行的事 ...
- 【.net 深呼吸】细说CodeDom(7):索引器
在开始正题之前,先补充一点前面的内容. 在方法中,如果要引用方法参数,前面的示例中,老周使用的是 CodeVariableReferenceExpression 类,它用于引用变量,也适用于引用方法参 ...
- SQLSERVER聚集索引与非聚集索引的再次研究(上)
SQLSERVER聚集索引与非聚集索引的再次研究(上) 上篇主要说聚集索引 下篇的地址:SQLSERVER聚集索引与非聚集索引的再次研究(下) 由于本人还是SQLSERVER菜鸟一枚,加上一些实验的逻 ...
- MySQL 系列(三)你不知道的 视图、触发器、存储过程、函数、事务、索引、语句
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...
- C# 索引器,实现IEnumerable接口的GetEnumerator()方法
当自定义类需要实现索引时,可以在类中实现索引器. 用Table作为例子,Table由多个Row组成,Row由多个Cell组成, 我们需要实现自定义的table[0],row[0] 索引器定义格式为 [ ...
- 【夯实Mysql基础】MySQL性能优化的21个最佳实践 和 mysql使用索引
本文地址 分享提纲: 1.为查询缓存优化你的查询 2. EXPLAIN 你的 SELECT 查询 3. 当只要一行数据时使用 LIMIT 1 4. 为搜索字段建索引 5. 在Join表的时候使用相当类 ...
- 开源 iOS 项目分类索引大全 - 待整理
开源 iOS 项目分类索引大全 GitHub 上大概600个开源 iOS 项目的分类和介绍,对于你挑选和使用开源项目应该有帮助 系统基础库 Category/Util sstoolkit 一套Cate ...
- SQL 数据优化索引建suo避免全表扫描
首先什么是全表扫描和索引扫描?全表扫描所有数据过一遍才能显示数据结果,索引扫描就是索引,只需要扫描一部分数据就可以得到结果.如果数据没建立索引. 无索引的情况下搜索数据的速度和占用内存就会比用索引的检 ...
随机推荐
- 一文详解如何在基于webpack5的react项目中使用svg
本文主要讨论基于webpack5+TypeScript的React项目(cra.craco底层本质都是使用webpack,所以同理)在2023年的今天是如何在项目中使用svg资源的. 首先,假定您已经 ...
- Redis 正则扫描key并删除
扫描key /** * @param key * @return * @Description: 通过Scan的方式迭代key */ public Set<String> scanKeys ...
- Java入门与进阶 P-2.1+P-2.2
比较运算符 关系运算符(relational operators)也可以称为"比较运算符",用于用来比较判断两个变量或常量的大小.关系运算符是二元运算符,运算结果是 boolean ...
- 同时打开多个.exe文件怎么解决
同时打开多个.exe文件怎么解决 小黑最近遇到一个问题,就是Unity封装好用来直接打开.exe的函数不好用了!! 怎么解决? 于是发现了.bat文件!好用至极啊 前提 小黑是征求过客户同意之后才这么 ...
- UML 图
类的表示(Class) 第一层:显示类的名称,如果是抽象类,则就用斜体显示. 第二层:是类的特性,通常就是字段和属性. 第三层:是类的操作,通常是方法或行为(前面加号(+)表示public:减号(-) ...
- 带你读AI论文丨S&P21 Survivalism: Living-Off-The-Land 经典离地攻击
摘要:这篇文章属于系统分析类的文章,通过详细的实验分析了离地攻击(Living-Off-The-Land)的威胁性和流行度,包括APT攻击中的利用及示例代码论证. 本文分享自华为云社区<[论文阅 ...
- 线程基础知识12-AQS
转:https://tech.meituan.com/2019/12/05/aqs-theory-and-apply.html 1 简介 AQS,全称AbstractQueuedSynchronize ...
- StatisticalOutlierRemoval:离群点移除
1.简介 StatisticalOutlierRemoval滤波器主要用于剔除离群点,或则测量误差导致的粗差点. 滤波思想为:对每一个点的邻域进行一个统计分析,计算它到所有临*点的*均距离.假设得到的 ...
- 关于Promise.all()的理解
本篇笔记是抄的别人的,目的只是为了日后有用到时有个参考,原文地址是https://www.jianshu.com/p/7e60fc1be1b2 一.Pomise.all的使用 Promise.all可 ...
- 图解论文《The Part-Time Parliament》
本文以图文并茂的方式重新演绎 Paxos 开山之作 <The Part-Time Parliament>[1],并尝试解释原论文中语焉不详的地方. 背景 在 Paxos 小岛上,施行着一种 ...