2013-04-12 22 views
5

bảng My lead có một chỉ số:Tại sao PostgreSQL (9.1) không sử dụng chỉ mục để chọn bình đẳng đơn giản?

\d lead 
... 
Indexes: 
    "lead_pkey" PRIMARY KEY, btree (id) 
    "lead_account__c" btree (account__c) 
    ... 
    "lead_email" btree (email) 
    "lead_id_prefix" btree (id text_pattern_ops) 

Tại sao không PG (9.1) sử dụng các chỉ số để lựa chọn bình đẳng đơn giản này? Email gần như tất cả các độc đáo ....

db=> explain select * from lead where email = 'blah'; 
         QUERY PLAN 
------------------------------------------------------------ 
Seq Scan on lead (cost=0.00..319599.38 rows=1 width=5108) 
    Filter: (email = 'blah'::text) 
(2 rows) 

khác chỉ số đánh thắc mắc dường như là OK (mặc dù tôi không biết tại sao người ta điều này không chỉ cần sử dụng chỉ số pkey):

db=> explain select * from lead where id = ''; 
            QUERY PLAN 
------------------------------------------------------------------------------ 
Index Scan using lead_id_prefix on lead (cost=0.00..8.57 rows=1 width=5108) 
    Index Cond: (id = ''::text) 
(2 rows) 

db=> explain select * from lead where account__c = ''; 
            QUERY PLAN 
---------------------------------------------------------------------------------- 
Index Scan using lead_account__c on lead (cost=0.00..201.05 rows=49 width=5108) 
    Index Cond: (account__c = ''::text) 
(2 rows) 

Lúc đầu, tôi nghĩ rằng nó có thể là do không đủ giá trị riêng biệt của email. Ví dụ: nếu số liệu thống kê cho rằng emailblah đối với hầu hết bảng, thì quét seq sẽ nhanh hơn. Nhưng đó không phải là trường hợp:

db=> select count(*), count(distinct email) from lead; 
count | count 
--------+-------- 
749148 | 733416 
(1 row) 

Thậm chí nếu tôi buộc quét seq để được giảm, các nhà quy hoạch cư xử như thể nó không có lựa chọn nào khác:

db=> set enable_seqscan = off; 
SET 
db=> show enable_seqscan; 
enable_seqscan 
---------------- 
off 
(1 row) 

db=> explain select * from lead where email = '[email protected]'; 
          QUERY PLAN 
--------------------------------------------------------------------------- 
Seq Scan on lead (cost=10000000000.00..10000319599.38 rows=1 width=5108) 
    Filter: (email = '[email protected]'::text) 
(2 rows) 

Cũng cố gắng EXPLAIN ANALYZE:

db=> explain analyze select * from lead where email = '[email protected]'; 
                 QUERY PLAN 
----------------------------------------------------------------------------------------------------------------------------- 
Seq Scan on lead (cost=10000000000.00..10000319732.76 rows=1 width=5102) (actual time=77845.244..77845.244 rows=0 loops=1) 
    Filter: (email = '[email protected]'::text) 
Total runtime: 77857.215 ms 
(3 rows) 

Đây là đầu ra \d (xin lỗi, phải che khuất tên cột và cắt để vừa với giới hạn của SO; xem phiên bản chưa được cắt tại http://pastebin.com/ve3gzJpY):

        Table "lead" 
        Column     |   Type    | Modifiers 
--------------------------------------------+-----------------------------+----------- 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | real      | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | text      | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | boolean      | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | text      | 
... 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | text      | 
email          | text      | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | boolean      | 
... 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | text      | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | text      | 
account__c         | text      | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | text      | 
... 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | text      | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | text      | 
id           | text      | not null 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | real      | 
... 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | timestamp without time zone | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | real      | 
Indexes: 
    "lead_pkey" PRIMARY KEY, btree (id) 
    "lead_account__c" btree (account__c) 
    "lead_XXXXXXXXXXXXXXXXXXXXXX" btree (XXXXXXXXXXXXXXXXXXXXXX) 
    "lead_XXXXXXXXXXXXXXXXXXXXXX" btree (XXXXXXXXXXXXXXXXXXXXXX) 
    "lead_XXXXXXXXXXXXXXXXXXXXXX" btree (XXXXXXXXXXXXXXXXXXXXXX) 
    "lead_email" btree (email) 
    "lead_id_prefix" btree (id text_pattern_ops) 

Đây là pg_dump --schema-only -t lead (một lần nữa nhìn thấy uncropped tại http://pastebin.com/ve3gzJpY, với tên cột độc đáo cũng như trong trường hợp nó giúp tái lập):

-- 
-- PostgreSQL database dump 
-- 

SET statement_timeout = 0; 
SET client_encoding = 'UTF8'; 
SET standard_conforming_strings = on; 
SET check_function_bodies = false; 
SET client_min_messages = warning; 

SET default_tablespace = ''; 

SET default_with_oids = false; 

-- 
-- Name: lead; Type: TABLE; Schema: public; Owner: pod; Tablespace: 
-- 

CREATE TABLE lead (
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX real, 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX text, 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX boolean, 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX text, 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX text, 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX date, 
    ... 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX text, 
    account__c text, 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX text, 
    ... 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX text, 
    id text NOT NULL, 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX real, 
    ... 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX timestamp without time zone, 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX real 
); 


ALTER TABLE lead OWNER TO pod; 

-- 
-- Name: lead_pkey; Type: CONSTRAINT; Schema: public; Owner: pod; Tablespace: 
-- 

ALTER TABLE ONLY lead 
    ADD CONSTRAINT lead_pkey PRIMARY KEY (id); 


-- 
-- Name: lead_account__c; Type: INDEX; Schema: public; Owner: pod; Tablespace: 
-- 

CREATE INDEX lead_account__c ON lead USING btree (account__c); 


-- 
-- Name: lead_XXXXXXXXXXXXXXXXXXXX; Type: INDEX; Schema: public; Owner: pod; Tablespace: 
-- 

CREATE INDEX lead_XXXXXXXXXXXXXXXXXXXX ON lead USING btree (XXXXXXXXXXXXXXXXXXXX); 


-- 
-- Name: lead_XXXXXXXXXXXXXXXXXXXX; Type: INDEX; Schema: public; Owner: pod; Tablespace: 
-- 

CREATE INDEX lead_XXXXXXXXXXXXXXXXXXXX ON lead USING btree (XXXXXXXXXXXXXXXXXXXX); 


-- 
-- Name: lead_XXXXXXXXXXXXXXXXXXXX; Type: INDEX; Schema: public; Owner: pod; Tablespace: 
-- 

CREATE INDEX lead_XXXXXXXXXXXXXXXXXXXX ON lead USING btree (XXXXXXXXXXXXXXXXXXXX); 


-- 
-- Name: lead_email; Type: INDEX; Schema: public; Owner: pod; Tablespace: 
-- 

CREATE INDEX lead_email ON lead USING btree (email); 


-- 
-- Name: lead_id_prefix; Type: INDEX; Schema: public; Owner: pod; Tablespace: 
-- 

CREATE INDEX lead_id_prefix ON lead USING btree (id text_pattern_ops); 


-- 
-- PostgreSQL database dump complete 
-- 

Một số catalogue PG bùa:

db=> select * from pg_index where indexrelid = 'lead_email'::regclass; 
indexrelid | indrelid | indnatts | indisunique | indisprimary | indisexclusion | indimmediate | indisclustered | indisvalid | indcheckxmin | indisready | indkey | indcollation | indclass | indoption | indexprs | indpred 
------------+-----------+----------+-------------+--------------+----------------+--------------+----------------+------------+--------------+------------+--------+--------------+----------+-----------+----------+--------- 
    215251995 | 101034456 |  1 | f   | f   | f    | t   | f    | t   | t   | t   | 101 | 100   | 10043 | 0   | ¤  | ¤ 
(1 row) 

Một số thông tin locale:

db=> show lc_collate; 
lc_collate 
------------- 
en_US.UTF-8 
(1 row) 

db=> show lc_ctype; 
    lc_ctype 
------------- 
en_US.UTF-8 
(1 row) 

Tôi đã tìm kiếm trên một số câu hỏi SO trong quá khứ nhưng không có câu hỏi nào về truy vấn bình đẳng đơn giản như câu hỏi này.

+1

Thật kỳ lạ ... bình đẳng đơn giản không cần chỉ mục 'text_pattern_ops', do đó khó giải thích. Bạn có thể tái tạo mẫu này trong một mẫu nhỏ không? Nếu vậy, hãy đăng lên sqlfiddle.com và liên kết tại đây. –

+1

Vui lòng hiển thị định nghĩa bảng đầy đủ (tốt nhất là thông qua 'pg_dump'). –

+0

@PeterEisentraut Cập nhật câu hỏi bằng lược đồ '\ d' và' pg_dump'. – Yang

Trả lời

0

TẠO INDEX lead_id_prefix TRÊN SỬ DỤNG btree (id text_pattern_ops);

Việc sử dụng text_pattern_ops có vẻ lạ ở đây. Nếu ID của bạn là một số loại số nguyên, tôi sẽ thử xóa chỉ mục này dưới dạng thử nghiệm. (Tôi sẽ không ngần ngại để thả chỉ số này trên một máy chủ phát triển.) Vì bạn có một chỉ số btree khác trên "lead.id", tôi mong đợi giảm chỉ số này để đánh dấu trình tối ưu hóa vào sử dụng chỉ mục khác trên "khách hàng tiềm năng .ID".

Nếu điều đó chứng tỏ là đúng, thì tôi sẽ cố gắng đào sâu hơn vào nguyên nhân.

+0

lưu ý truy vấn vấn đề là trên email cột, không phải trên id. – alvherre

+0

Ha! Tôi đọc quá khứ "nơi email = 'blah'" đến "nơi id = ''", và "id" bị mắc kẹt trong đầu của tôi! –

1

Để khắc phục sự cố này, bạn bắt buộc phải chạy VACUUM ANALYZE trên bảng giữa các bước khắc phục sự cố để xem điều gì hoạt động. Nếu không, bạn có thể không biết chính xác những gì đã thay đổi ở đâu. Vì vậy, hãy thử điều đó và chạy lại trước và xem có khắc phục được sự cố hay không.

Các bước tiếp theo để chạy (chạy chân không phân tích và trường hợp atest giữa mỗi người) là:

ALTER TABLE lead ALTER COLUMN email SET STATISTICS 1000; 

Có lẽ đó sẽ sửa chữa nó. Có thể không.

Nếu điều đó không sửa chữa nó, hãy nhìn kỹ xem pg_stat:

SELECT * FROM pg_stat WHERE table_name = 'lead'; 

hãy đọc phần sau đây kỹ lưỡng và xem những gì bạn có thể thấy rằng không ổn trong pg_stat;

http://www.postgresql.org/docs/9.0/static/planner-stats.html

EDIT: Để được rất rõ ràng, vacuum analyse không phải là toàn bộ gỡ rối. Tuy nhiên, nó phải được chạy giữa các bước khắc phục sự cố bởi vì nếu không bạn không thể chắc chắn rằng người lập kế hoạch có tính đến dữ liệu chính xác hay không.

+0

Vấn đề đã biến mất một cách bí ẩn khi nó đến, nhưng đáng chú ý là tôi đã thử chạy 'VACUUM ANALYZE' - rất nhiều. – Yang

+0

Vấn đề là chạy nó giữa các bước khắc phục sự cố để đảm bảo rằng máy phân tích đang sử dụng các cài đặt hiện tại, v.v. –

Các vấn đề liên quan