File: usage.rst

package info (click to toggle)
hypopg 1.4.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 464 kB
  • sloc: ansic: 2,338; sql: 357; makefile: 66; python: 51; sh: 2
file content (392 lines) | stat: -rw-r--r-- 13,664 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
.. _usage:

Usage
=====

Introduction
------------

HypoPG is useful if you want to check if some index would help one or multiple
queries.  Therefore, you should already know what are the queries you need to
optimize, and ideas on which indexes you want to try.

Also, the hypothetical indexes that HypoPG will create are not stored in any
catalog, but in your connection private memory.  Therefore, it won't bloat any
table and won't impact any concurrent connection.

Also, since the hypothetical indexes doesn't really exists, HypoPG makes sure
they will only be used using a simple EXPLAIN statement (without the ANALYZE
option).

Install the extension
---------------------

As any other extension, you have to install it on all the databases where you
want to be able to use it.  This is simply done executing the following query,
connected on the database you want to install HypoPG with a user having enough
privileges:

.. code-block:: psql

  CREATE EXTENSION hypopg ;

HypoPG is now available.  You can check easily if the extension is present
using `psql <https://www.postgresql.org/docs/current/static/app-psql.html>`_:

.. code-block:: psql
  :emphasize-lines: 5

  \dx
                       List of installed extensions
    Name   | Version |   Schema   |             Description
  ---------+---------+------------+-------------------------------------
   hypopg  | 1.1.0   | public     | Hypothetical indexes for PostgreSQL
   plpgsql | 1.0     | pg_catalog | PL/pgSQL procedural language
  (2 rows)

As you can see, hypopg version 1.1.0 is installed.  If you need to check using
plain SQL, please refer to the `pg_extension table documentation
<https://www.postgresql.org/docs/current/static/catalog-pg-extension.html>`_.

Configuration
-------------

The following configuration parameters (GUCs) are available, and can be changed
interactively:

hypopg.enabled:
  Default to ``on``.
  Use this parameter to globally enable or disable HypoPG.  When HypoPG is
  disabled, no hypothetical index will be used, but the defined hypothetical
  indexes won't be removed.

hypopg.use_real_oids:
  Default to ``off``.
  By default, HypoPG won't use "real" object identifiers, but instead borrow
  ones from the ~ 14000 / 16384 (respectively the lowest unused oid less then
  FirstNormalObjectId and FirstNormalObjectId) range, which are reserved by
  PostgreSQL for future usage in future releases.  This doesn't cause any
  problem, as the free range is dynamically computed the first time a
  connection uses HypoPG, and has the advantage to work on a standby server.
  But the drawback is that you can't have more than approximately 2500
  hypothetical indexes at the same time, and creating a new hypothetical index
  will become very slow once more than the maximum number of objects has been
  created until ``hypopg_reset()`` is called.

  If those drawbacks are problematic, you can enable this parameter.  HypoPG
  will then ask for a real object identifier, which will need to obtain more
  locks and won't work on a standby, but will allow to use the full range of
  object identifiers.

  Note that switching this parameter doesn't require to reset the entries, both
  can coexist at the same time.

Supported access methods
------------------------

The following access methods are supported:

- btree
- brin
- hash (requires PostgreSQL 10 or above)
- bloom (requires the bloom extension to be installed)

Create a hypothetical index
---------------------------

.. note::

  Using HypoPG require some knowledge on the **EXPLAIN** command.  If you need
  more information about this command, you can check `the official
  documentation
  <https://www.postgresql.org/docs/current/static/using-explain.html>`_.  There
  are also a lot of very good resources available.

For clarity, let's see how it works with a very simple test case:

.. code-block:: psql

  CREATE TABLE hypo (id integer, val text) ;
  INSERT INTO hypo SELECT i, 'line ' || i FROM generate_series(1, 100000) i ;
  VACUUM ANALYZE hypo ;

This table doesn't have any index.  Let's assume we want to check if an index
would help a simple query.  First, let's see how it behaves:

.. code-block:: psql

  EXPLAIN SELECT val FROM hypo WHERE id = 1;
                         QUERY PLAN
  --------------------------------------------------------
   Seq Scan on hypo  (cost=0.00..1791.00 rows=1 width=14)
     Filter: (id = 1)
  (2 rows)

A plain sequential scan is used, since no index exists on the table.  A simple
btree index on the **id** column should help this query.  Let's check with
HypoPG.  The function **hypopg_create_index()** will accept any standard
**CREATE INDEX** statement(s) (any other statement passed to this function will be
ignored), and create a hypothetical index for each:

.. code-block:: psql

  SELECT * FROM hypopg_create_index('CREATE INDEX ON hypo (id)') ;
   indexrelid |      indexname
  ------------+----------------------
        18284 | <18284>btree_hypo_id
  (1 row)

The function returns two columns:

- the object identifier of the hypothetical index
- the generated hypothetical index name

We can run the EXPLAIN again to see if PostgreSQL would use this index:

.. code-block:: psql
  :emphasize-lines: 4

  EXPLAIN SELECT val FROM hypo WHERE id = 1;
                                      QUERY PLAN
  ----------------------------------------------------------------------------------
   Index Scan using <18284>btree_hypo_id on hypo  (cost=0.04..8.06 rows=1 width=10)
     Index Cond: (id = 1)
  (2 rows)

Yes, PostgreSQL would use such an index.  Just to be sure, let's check that the
hypothetical index won't be used to acually run the query:

.. code-block:: psql

  EXPLAIN ANALYZE SELECT val FROM hypo WHERE id = 1;
                                              QUERY PLAN
  ---------------------------------------------------------------------------------------------------
   Seq Scan on hypo  (cost=0.00..1791.00 rows=1 width=10) (actual time=0.046..46.390 rows=1 loops=1)
     Filter: (id = 1)
     Rows Removed by Filter: 99999
   Planning time: 0.160 ms
   Execution time: 46.460 ms
  (5 rows)

That's all you need to create hypothetical indexes and see if PostgreSQL would
use such indexes.

Manipulate hypothetical indexes
-------------------------------

Some other convenience functions and views are available:

- **hypopg_list_indexes**: view that lists all hypothetical indexes that have
  been created

.. code-block:: psql

  SELECT * FROM hypopg_list_indexes ;
   indexrelid |      index_name       | schema_name | table_name | am_name
  ------------+-----------------------+-------------+------------+---------
        18284 | <18284>btree_hypo_id  | public      | hypo       | btree
  (1 row)

- **hypopg()**: function that lists all hypothetical indexes that have
  been created with the same format as **pg_index**

.. code-block:: psql

  SELECT * FROM hypopg() ;
        indexname       | indexrelid | indrelid | innatts | indisunique | indkey | indcollation | indclass | indoption | indexprs | indpred | amid
  ----------------------+------------+----------+---------+-------------+--------+--------------+----------+-----------+----------+---------+------
   <18284>btree_hypo_id |      13543 |    18122 |       1 | f           | 1      | 0            | 1978     | <NULL>    | <NULL>   | <NULL>  |  403
  (1 row)

- **hypopg_get_indexdef(oid)**: function that lists the CREATE INDEX statement
  that would recreate a stored hypothetical index

.. code-block:: psql

  SELECT index_name, hypopg_get_indexdef(indexrelid) FROM hypopg_list_indexes ;
        index_name       |             hypopg_get_indexdef
  -----------------------+----------------------------------------------
   <18284>btree_hypo_id  | CREATE INDEX ON public.hypo USING btree (id)
  (1 row)

- **hypopg_relation_size(oid)**: function that estimates how big a hypothetical
  index would be:

.. code-block:: psql

  SELECT index_name, pg_size_pretty(hypopg_relation_size(indexrelid))
    FROM hypopg_list_indexes ;
        index_name       | pg_size_pretty
  -----------------------+----------------
   <18284>btree_hypo_id  | 2544 kB
  (1 row)

- **hypopg_drop_index(oid)**: function that removes the given hypothetical
  index
- **hypopg_reset()**: function that removes all hypothetical indexes

Hypothetically hide existing indexes
------------------------------------

You can hide both existing and hypothetical indexes hypothetically.
If you want to test it as described in the documentation,
you should first use **hypopg_reset()** to clear the effects of any other hypothetical indexes.

As a simple case, let's consider two indexes:

.. code-block:: psql

  SELECT hypopg_reset();
  CREATE INDEX ON hypo(id);
  CREATE INDEX ON hypo(id, val);

.. code-block:: psql
  :emphasize-lines: 4

  EXPLAIN SELECT * FROM hypo WHERE id = 1;
                                      QUERY PLAN
  ----------------------------------------------------------------------------------
  Index Only Scan using hypo_id_val_idx on hypo  (cost=0.29..8.30 rows=1 width=13)
  Index Cond: (id = 1)
  (2 rows)

The query plan is using the **hypo_id_val_idx** index now.

- **hypopg_hide_index(oid)**: function that allows you to hide an index in the EXPLAIN output by using its OID.
  It returns `true` if the index was successfully hidden, and `false` otherwise.

.. code-block:: psql
  :emphasize-lines: 10

  SELECT hypopg_hide_index('hypo_id_val_idx'::REGCLASS);
   hypopg_hide_index
  -------------------
  t
  (1 row)

  EXPLAIN SELECT * FROM hypo WHERE id = 1;
                              QUERY PLAN
  -------------------------------------------------------------------------
  Index Scan using hypo_id_idx on hypo  (cost=0.29..8.30 rows=1 width=13)
  Index Cond: (id = 1)
  (2 rows)

As an example, let's assume that the query plan is currently using the **hypo_id_val_idx** index.
To continue testing, use the **hypopg_hide_index(oid)** function to hide another index.

.. code-block:: psql
  :emphasize-lines: 10

  SELECT hypopg_hide_index('hypo_id_idx'::REGCLASS);
   hypopg_hide_index
  -------------------
  t
  (1 row)

  EXPLAIN SELECT * FROM hypo WHERE id = 1;
                      QUERY PLAN
  -------------------------------------------------------
  Seq Scan on hypo  (cost=0.00..180.00 rows=1 width=13)
  Filter: (id = 1)
  (2 rows)

- **hypopg_unhide_index(oid)**: function that restore a previously hidden index in the EXPLAIN output by using its OID.
  It returns `true` if the index was successfully restored, and `false` otherwise.

.. code-block:: psql
  :emphasize-lines: 10

  SELECT hypopg_unhide_index('hypo_id_idx'::regclass);
   hypopg_unhide_index
  -------------------
  t
  (1 row)

  EXPLAIN SELECT * FROM hypo WHERE id = 1;
                              QUERY PLAN
  -------------------------------------------------------------------------
  Index Scan using hypo_id_idx on hypo  (cost=0.29..8.30 rows=1 width=13)
  Index Cond: (id = 1)
  (2 rows)

- **hypopg_unhide_all_index()**: function that restore all hidden indexes and returns void.

- **hypopg_hidden_indexes()**: function that returns a list of OIDs for all hidden indexes.

.. code-block:: psql

  SELECT * FROM hypopg_hidden_indexes();
   indexid
  ---------
  526604
  (1 rows)

- **hypopg_hidden_indexes**: view that returns a formatted list of all hidden indexes.

.. code-block:: psql

  SELECT * FROM hypopg_hidden_indexes;
    indexrelid |      index_name      | schema_name | table_name | am_name | is_hypo
  -------------+----------------------+-------------+------------+---------+---------
        526604 | hypo_id_val_idx      | public      | hypo       | btree   | f
  (1 rows)

.. note::

  Hypothetical indexes can be hidden as well.

.. code-block:: psql
  :emphasize-lines: 10

  SELECT hypopg_create_index('CREATE INDEX ON hypo(id)');
      hypopg_create_index
  ------------------------------
  (12659,<12659>btree_hypo_id)
  (1 row)

  EXPLAIN SELECT * FROM hypo WHERE id = 1;
                                      QUERY PLAN
  ------------------------------------------------------------------------------------
  Index Scan using "<12659>btree_hypo_id" on hypo  (cost=0.04..8.05 rows=1 width=13)
  Index Cond: (id = 1)
  (2 rows)

Now that the hypothetical index is being used, we can try hiding it to see the change:

.. code-block:: psql
  :emphasize-lines: 10

  SELECT hypopg_hide_index(12659);
   hypopg_hide_index
  -------------------
  t
  (1 row)

  EXPLAIN SELECT * FROM hypo WHERE id = 1;
                              QUERY PLAN
  -------------------------------------------------------------------------
  Index Scan using hypo_id_idx on hypo  (cost=0.29..8.30 rows=1 width=13)
  Index Cond: (id = 1)
  (2 rows)

  SELECT * FROM hypopg_hidden_indexes;
    indexrelid |      index_name      | schema_name | table_name | am_name | is_hypo
  -------------+----------------------+-------------+------------+---------+---------
         12659 | <12659>btree_hypo_id | public      | hypo       | btree   | t
        526604 | hypo_id_val_idx      | public      | hypo       | btree   | f
  (2 rows)

.. note::

  If a hypothetical index has been hidden, it will be automatically unhidden
  when it is deleted using **hypopg_drop_index(oid)** or **hypopg_reset()**.

.. code-block:: psql

  SELECT hypopg_drop_index(12659);

  SELECT * FROM hypopg_hidden_indexes;
    indexrelid |      index_name      | schema_name | table_name | am_name | is_hypo
  -------------+----------------------+-------------+------------+---------+---------
        526604 | hypo_id_val_idx      | public      | hypo       | btree   | f
  (2 rows)