Обсуждение: btree index on a char(8) field (fwd)

Поиск
Список
Период
Сортировка

btree index on a char(8) field (fwd)

От
Frank Mandarino
Дата:
Hi,

I sent out the forwarded message below last Sunday, and have received no
responses.

Now I realize that this list operates on a volunteer basis and that
everyone is busy, so I am in no way demanding or expecting an answer,
but I would really like to know if there is something wrong with the
message that caused the lack of response.

Does it contain too much or too little detail?  Is it an obvious RTFM
question?  Is this is the correct mailing list?

Basically, I am trying to make use of a btree index on a char(8) field,
the optimizer doesn't want to use it, and I would like to know why.

I was hoping that there might be a simple explanation.  I have searched
the PostgreSQL documentation and the mailing list archives without
success.

I would *greatly* appreciate any response to this message or the
forwarded message, no matter how brief.

Thanks in advance,
../fam

---------- Forwarded message ----------
Date: Sun, 3 Oct 1999 19:50:37 -0400
From: Frank Mandarino <fam@dbsys.risca.com>
To: pgsql-general@postgreSQL.org
Subject: [GENERAL] btree index on a char(8) field

I am in the process of migrating a database from Postgres95 2.0 to
PostgreSQL 6.5.2 on a Debian 2.1 system.

In a few of the tables, a char8 type field was used for the primary key,
so I converted them to type char(8).  The tables also had a btree index
built on the primary key using char8_ops, which I converted to char_ops.

Now I am finding that explain is indicating that the index is never
used, even for queries that I would have thought would run faster using
an index.

For example:

main=> \d vendor
Table    = vendor
+----------------------------------+----------------------------------+-------+
|              Field               |              Type                | Length|
+----------------------------------+----------------------------------+-------+
| ven_code                         | char()                           |     8 |
| initials                         | char()                           |     2 |
| tax_number                       | text                             |   var |
| check_payable_to                 | text                             |   var |
| other_name                       | text                             |   var |
| address_1                        | text                             |   var |
| address_2                        | text                             |   var |
| city                             | text                             |   var |
| ps                               | text                             |   var |
| country                          | text                             |   var |
| postal_code                      | text                             |   var |
| work_phone                       | text                             |   var |
| home_phone                       | text                             |   var |
| fax_phone                        | text                             |   var |
| bank_code                        | text                             |   var |
| trans_num                        | text                             |   var |
| bank_acc_num                     | text                             |   var |
| payment_restriction_flag         | char()                           |     1 |
| debt_reason_msg                  | text                             |   var |
| debt_caution_msg                 | text                             |   var |
| comments_1                       | text                             |   var |
| comments_2                       | text                             |   var |
| special_order                    | char()                           |     1 |
| status                           | char()                           |     1 |
+----------------------------------+----------------------------------+-------+

main=> select count(*) from vendor;
count
-----
 9905
(1 row)

main=> create index ven_code_idx on vendor using btree (ven_code char_ops);
CREATE
main=> vacuum analyze;
VACUUM
main=> explain select ven_code,initials,city from vendor where ven_code='P8979';
NOTICE:  QUERY PLAN:

Seq Scan on vendor  (cost=738.86 rows=2 width=36)

EXPLAIN
main=>


Under Postgres95, the index was used from such queries.  Can anyone tell
me why the index isn't being used in PostgreSQL?

Thanks,
../fam
--
Frank A. Mandarino
fam@risca.com


************



Re: [GENERAL] btree index on a char(8) field (fwd)

От
Herouth Maoz
Дата:
At 15:30 +0200 on 06/10/1999, Frank Mandarino wrote:


> main=> create index ven_code_idx on vendor using btree (ven_code char_ops);
> CREATE

I didn't have time to check this, but the problem may be caused by the
incorrect ops you are using. For char(N) it should be bpchar_ops, not
char_ops.

Herouth

--
Herouth Maoz, Internet developer.
Open University of Israel - Telem project
http://telem.openu.ac.il/~herutma



Re: [GENERAL] btree index on a char(8) field (fwd)

От
Frank Mandarino
Дата:
Hermouth,

Thank you so much for your reply!  You were exactly right.  I re-created
the index with bpchar_ops, and explain now outputs:

    Index Scan using ven_code_idx on vendor  (cost=2.05 rows=2 width=36)

instead of

    Seq Scan on vendor  (cost=738.86 rows=2 width=36)

Queries are obviously much faster now.

I am unable to find any reference to bpchar_ops in the the documentation
or the General and SQL mailing list archives.  Can you tell me where I
could find out more about what "_ops" are available and what they all
mean?

Thanks again,
../fam
--
Frank A. Mandarino
fam@risca.com


On Wed, 6 Oct 1999, Herouth Maoz wrote:

> At 15:30 +0200 on 06/10/1999, Frank Mandarino wrote:
>
>
> > main=> create index ven_code_idx on vendor using btree (ven_code char_ops);
> > CREATE
>
> I didn't have time to check this, but the problem may be caused by the
> incorrect ops you are using. For char(N) it should be bpchar_ops, not
> char_ops.
>
> Herouth
>
> --
> Herouth Maoz, Internet developer.
> Open University of Israel - Telem project
> http://telem.openu.ac.il/~herutma
>
>
>
> ************
>



Re: [GENERAL] btree index on a char(8) field (fwd)

От
"Gene Selkov, Jr."
Дата:
> I am unable to find any reference to bpchar_ops in the the documentation
> or the General and SQL mailing list archives.  Can you tell me where I
> could find out more about what "_ops" are available and what they all
> mean?

The direct answer:

$ pwd
/usr/src/postgresql-6.5/doc/src/sgml
$ find -name "*sgml" -exec grep -il "_ops" {} \;
./ref/create_index.sgml
./arch-dev.sgml  -- irrelevant: co-incidental with a processing directive, \label{simple_set_ops})
./bki.sgml
./gist.sgml
./xindex.sgml

My comment:

The deficiency of the docs in regards to operator classes probably
results from the fact that no one is asking about those. The opclass
parameter in CREATE INDEX is no longer required (Herouth has been
around long enough to recall the times when it was).

As you have just witnessed, in a standard situation, you are better
off without knowing about it -- postgres will pick the right opclass
for you. That will not happen, however, when the values you want to
index are of a custom type, or when a built-in type does not have an
opclass of its own (as is the case with the point type). Also, you
need this option to override the default opclass for those types that
can work with multiple opclasses (which is what you attempted to
achieve).

Will anyone with a solid knowledge of the type system want to augment
the existing docs?

--Gene

Re: [GENERAL] btree index on a char(8) field (fwd)

От
Frank Mandarino
Дата:
Gene,

Thanks for your response.

I knew from the programming documentation that the opclass was optional.
I'm pretty sure, although I will check again tonight, that I tried
creating the index without specifying the opclass, but I found that the
index was still not used in my example query.

Do you know which opclass that Postgres should choose for char(8) types?

Regards,
../fam
--
Frank A. Mandarino
fam@risca.com


On Thu, 7 Oct 1999, Gene Selkov, Jr. wrote:

>
> My comment:
>
> The deficiency of the docs in regards to operator classes probably
> results from the fact that no one is asking about those. The opclass
> parameter in CREATE INDEX is no longer required (Herouth has been
> around long enough to recall the times when it was).
>
> As you have just witnessed, in a standard situation, you are better
> off without knowing about it -- postgres will pick the right opclass
> for you. That will not happen, however, when the values you want to
> index are of a custom type, or when a built-in type does not have an
> opclass of its own (as is the case with the point type). Also, you
> need this option to override the default opclass for those types that
> can work with multiple opclasses (which is what you attempted to
> achieve).
>
> Will anyone with a solid knowledge of the type system want to augment
> the existing docs?
>
> --Gene
>
> ************
>


Re: [GENERAL] btree index on a char(8) field (fwd)

От
Frank Mandarino
Дата:
On Thu, 7 Oct 1999, Frank Mandarino wrote:

> Gene,
>
> Thanks for your response.
>
> I knew from the programming documentation that the opclass was optional.
> I'm pretty sure, although I will check again tonight, that I tried
> creating the index without specifying the opclass, but I found that the
> index was still not used in my example query.
>
> Do you know which opclass that Postgres should choose for char(8) types?
>
> Regards,
> ../fam
>

--
Frank A. Mandarino                fam@risca.com
Infrasoft Inc.
(905) 877-1752    Days: (416) 350-5261


Re: [GENERAL] btree index on a char(8) field (fwd)

От
"Gene Selkov, Jr."
Дата:
Frank Mandarino wrote:

> Thanks for your response.
>
> I knew from the programming documentation that the opclass was optional.
> I'm pretty sure, although I will check again tonight, that I tried
> creating the index without specifying the opclass, but I found that the
> index was still not used in my example query.
>
> Do you know which opclass that Postgres should choose for char(8) types?

Owing very much to Franks question, I looked around and made the
following discovery. I have always been puzzled why only my own types
require an opclass in CREATE INDEX. The answer is that I failed to
provide the default. I based my code on the outdated postgres schema,
which still exists in the docs:

http://www.postgresql.org/docs/programmer/extend289.htm
(I'd love to see it fixed one day!)

If I got it right, the default opclass is snow specified in pg_opclass:

SELECT DISTINCT pg_am.amname, pg_opclass.opcname, pg_type.typname
FROM pg_am, pg_amop, pg_opclass, pg_type
WHERE pg_amop.amopid = pg_am.oid
  AND pg_amop.amopclaid = pg_opclass.oid
  AND pg_opclass.opcdeftype = pg_type.oid;

amname|opcname     |typname
------+------------+--------
btree |abstime_ops |abstime
btree |bpchar_ops  |bpchar
btree |char_ops    |char
btree |date_ops    |date
btree |datetime_ops|datetime
btree |float4_ops  |float4
btree |float8_ops  |float8
btree |int2_ops    |int2
btree |int4_ops    |int4
btree |int8_ops    |int8
btree |macaddr_ops |macaddr
btree |name_ops    |name
btree |network_ops |cidr
btree |network_ops |inet
btree |oid8_ops    |oid8
btree |oid_ops     |oid
btree |text_ops    |text
btree |time_ops    |time
btree |timespan_ops|timespan
btree |varchar_ops |varchar
hash  |bpchar_ops  |bpchar
hash  |char_ops    |char
hash  |date_ops    |date
hash  |datetime_ops|datetime
hash  |float4_ops  |float4
hash  |float8_ops  |float8
hash  |int2_ops    |int2
hash  |int4_ops    |int4
hash  |int8_ops    |int8
hash  |macaddr_ops |macaddr
hash  |name_ops    |name
hash  |network_ops |cidr
hash  |network_ops |inet
hash  |oid8_ops    |oid8
hash  |oid_ops     |oid
hash  |text_ops    |text
hash  |time_ops    |time
hash  |timespan_ops|timespan
hash  |varchar_ops |varchar
rtree |bigbox_ops  |box
rtree |box_ops     |box
rtree |circle_ops  |circle
rtree |poly_ops    |polygon
(43 rows)

The way I understand it is that for each access method (amname) and
data type (typname) the default opclass is specified in
(opcname). This doesn't tell you, however, that char(n) is a bpchar
(thanks to SQL92 compliance, you can't anymore find that out by just
looking at it). Also, the above query does not list the types not
having a default opclass:

SELECT * FROM pg_opclass WHERE opcdeftype IS NULL;
opcname     |opcdeftype
------------+----------
ec_code_ops |
gist_seg_ops|

And by the way, what I have just found makes me believe that one does
not even have to mention the access method ("using"-clause) in their
CREATE INDEX.

"If nothing else helps, read the manual"

--Gene