سؤال

أحاول تشغيل وظيفة البحث عن النص الكامل في postgres.

لدي جدولان، أحدهما أنشأته للاختبار فقط، والآخر الفعلي الذي أريد أن أتمكن من البحث فيه:

جدول الاختبار:

webarchive=# \d test_sites
                            Table "public.test_sites"
   Column    |   Type   |                        Modifiers
-------------+----------+---------------------------------------------------------
 id          | integer  | not null default nextval('test_sites_id_seq'::regclass)
 content     | text     |
 tsv_content | tsvector |
Indexes:
    "test_sites_pkey" PRIMARY KEY, btree (id)
    "idx_test_web_pages_content" gin (tsv_content)
Triggers:
    web_pages_testing_content_change_trigger AFTER INSERT OR UPDATE ON test_sites FOR EACH ROW EXECUTE PROCEDURE web_pages_testing_content_update_func()

الجدول "الحقيقي":

webarchive=# \d web_pages
                                      Table "public.web_pages"
    Column    |            Type             |                       Modifiers
--------------+-----------------------------+--------------------------------------------------------
 id           | integer                     | not null default nextval('web_pages_id_seq'::regclass)
 state        | dlstate_enum                | not null
 errno        | integer                     |
 url          | text                        | not null
 starturl     | text                        | not null
 netloc       | text                        | not null
 file         | integer                     |
 priority     | integer                     | not null
 distance     | integer                     | not null
 is_text      | boolean                     |
 limit_netloc | boolean                     |
 title        | citext                      |
 mimetype     | text                        |
 type         | itemtype_enum               |
 raw_content  | text                        |
 content      | text                        |
 fetchtime    | timestamp without time zone |
 addtime      | timestamp without time zone |
 tsv_content  | tsvector                    |
Indexes:
    "web_pages_pkey" PRIMARY KEY, btree (id)
    "ix_web_pages_url" UNIQUE, btree (url)
    "idx_web_pages_content" gin (tsv_content)
    "idx_web_pages_title" gin (to_tsvector('english'::regconfig, title::text))
    "ix_web_pages_distance" btree (distance)
    "ix_web_pages_distance_filtered" btree (priority) WHERE state = 'new'::dlstate_enum AND distance < 1000000
    "ix_web_pages_priority" btree (priority)
    "ix_web_pages_type" btree (type)
    "ix_web_pages_url_ops" btree (url text_pattern_ops)
Foreign-key constraints:
    "web_pages_file_fkey" FOREIGN KEY (file) REFERENCES web_files(id)
Triggers:
    web_pages_content_change_trigger AFTER INSERT OR UPDATE ON web_pages FOR EACH ROW EXECUTE PROCEDURE web_pages_content_update_func()

وبغض النظر عن البتات الإضافية، فكلاهما يحتوي على content العمود، و tsv_content عمود مع أ gin() مؤشر عليه.هناك مشغل يقوم بتحديث tsv_content العمود في كل مرة content تم تعديل العمود.

نلاحظ أن آخر gin يعمل الفهرس بشكل جيد، وفي الواقع كان لدي في البداية ملف gin (to_tsvector('english'::regconfig, content::text)) فهرس في عمود المحتويات أيضًا، بدلاً من العمود الثاني، ولكن بعد انتظار إعادة بناء هذا الفهرس عدة مرات في الاختبار، قررت استخدام عمود منفصل لتخزين قيم tsvector مسبقًا.

تنفيذ استعلام مقابل جدول الاختبار يستخدم الفهرس كما أتوقع:

webarchive=# EXPLAIN ANALYZE SELECT
    test_sites.id,
    test_sites.content,
    ts_rank_cd(test_sites.tsv_content, to_tsquery($$testing$$)) AS ts_rank_cd_1
FROM
    test_sites
WHERE
    test_sites.tsv_content @@ to_tsquery($$testing$$);
                                                              QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on test_sites  (cost=16.45..114.96 rows=25 width=669) (actual time=0.175..3.720 rows=143 loops=1)
   Recheck Cond: (tsv_content @@ to_tsquery('testing'::text))
   Heap Blocks: exact=117
   ->  Bitmap Index Scan on idx_test_web_pages_content  (cost=0.00..16.44 rows=25 width=0) (actual time=0.109..0.109 rows=143 loops=1)
         Index Cond: (tsv_content @@ to_tsquery('testing'::text))
 Planning time: 0.414 ms
 Execution time: 3.800 ms
(7 rows)

ومع ذلك، مثلها بالضبط لا يبدو أن الاستعلام على الجدول الحقيقي يؤدي إلى أي شيء لكن مسح تسلسلي قديم عادي:

webarchive=# EXPLAIN ANALYZE SELECT
       web_pages.id,
       web_pages.content,
       ts_rank_cd(web_pages.tsv_content, to_tsquery($$testing$$)) AS ts_rank_cd_1
   FROM
       web_pages
   WHERE
       web_pages.tsv_content @@ to_tsquery($$testing$$);
                                                       QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
 Seq Scan on web_pages  (cost=0.00..4406819.80 rows=19751 width=505) (actual time=0.343..142325.954 rows=134949 loops=1)
   Filter: (tsv_content @@ to_tsquery('testing'::text))
   Rows Removed by Filter: 12764373
 Planning time: 0.436 ms
 Execution time: 142341.489 ms
(5 rows)

لقد قمت بزيادة ذاكرة العمل الخاصة بي إلى 3 غيغابايت لمعرفة ما إذا كانت هذه هي المشكلة أم لا.

بالإضافة إلى ذلك، تجدر الإشارة إلى أن هذه الجداول كبيرة إلى حد ما - حوالي 150 جيجابايت من النص عبر 4 ملايين صف (مع 8 ملايين صف إضافي حيث content/tsv_content يكون NULL).

ال test_sites يحتوي الجدول على 1/1000 من صفوف web_pages, ، نظرًا لأنه يعد أمرًا محظورًا بعض الشيء للتجربة عندما يستغرق كل استعلام عدة دقائق.


أنا أستخدم postgresql 9.5 (نعم، قمت بتجميعه بنفسي، أردت ذلك ON CONFLICT).لا يبدو أن هناك علامة لذلك حتى الآن.

لقد قرأت من خلال القضايا المفتوحة مع 9.5، ولا أستطيع أن أرى أن هذا نتيجة لأي منها.


بعد إعادة بناء الفهرس بالكامل، لا تزال المشكلة موجودة:

webarchive=# ANALYZE web_pages ;
ANALYZE
webarchive=# EXPLAIN ANALYZE SELECT
    web_pages.id,
    web_pages.content,
    ts_rank_cd(web_pages.tsv_content, to_tsquery($$testing$$)) AS ts_rank_cd_1
FROM
    web_pages
WHERE
    web_pages.tsv_content @@ to_tsquery($$testing$$);
                                                              QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on web_pages  (cost=10000000000.00..10005252343.30 rows=25109 width=561) (actual time=7.114..146444.168 rows=134949 loops=1)
   Filter: (tsv_content @@ to_tsquery('testing'::text))
   Rows Removed by Filter: 13137318
 Planning time: 0.521 ms
 Execution time: 146465.188 ms
(5 rows)

لاحظ أنني حرفيا فقط ANALYZEإد، وتم تعطيل seqscan.

هل كانت مفيدة؟

المحلول

حسنًا، لقد أمضيت بعض الوقت في توفير مساحة إضافية على القرص باستخدام قاعدة البيانات، ونقل بعض قواعد البيانات الأخرى إلى SSD آخر.

ثم ركضت VACUUM ANALYZE عبر قاعدة البيانات بأكملها, والآن يبدو أنه لاحظ أن لدي ملف Index.

لقد سبق لي أن قمت بتحليلها وتنظيفها بالمكنسة الكهربائية فقط هذا الجدول, ، ولكن يبدو أنه أحدث فرقًا بطريقة ما في القيام بذلك بشكل عام بدلاً من جدول معين.إذهب واستنتج.

webarchive=# EXPLAIN ANALYZE SELECT
    web_pages.id,
    web_pages.content
FROM
    web_pages
WHERE
    web_pages.tsv_content @@ to_tsquery($$testing$$);
                                                                 QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on web_pages  (cost=1185.79..93687.30 rows=23941 width=189) (actual time=41.448..152.108 rows=134949 loops=1)
   Recheck Cond: (tsv_content @@ to_tsquery('testing'::text))
   Heap Blocks: exact=105166
   ->  Bitmap Index Scan on idx_web_pages_content  (cost=0.00..1179.81 rows=23941 width=0) (actual time=24.940..24.940 rows=134996 loops=1)
         Index Cond: (tsv_content @@ to_tsquery('testing'::text))
 Planning time: 0.452 ms
 Execution time: 154.942 ms
(7 rows)

كما انتهزت الفرصة لتشغيل VACUUM FULL; الآن بعد أن أصبح لدي مساحة كافية للمعالجة.لقد واجهت قدرًا لا بأس به من التقلب في الصفوف في الجدول أثناء تجربتي أثناء التطوير وأود أن أحاول دمج أي تجزئة للملف نتجت عن ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى dba.stackexchange
scroll top