PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

प्रत्येक व्यक्तिगत पहचानकर्ता के लिए नवीनतम पंक्ति तक पहुँचने का उचित तरीका?

इस पोस्ट में उल्लिखित प्रश्नों के लिए त्वरित प्रदर्शन तुलना यहां दी गई है।

वर्तमान सेटअप :

तालिका core_message 10,904,283 पंक्तियाँ हैं और test_boats . में 60,740 पंक्तियाँ हैं (या core_message . में 60,740 विशिष्ट mmsi )।

और मैं PostgreSQL 11.5 का उपयोग कर रहा हूं

केवल-अनुक्रमणिका स्कैन का उपयोग कर क्वेरी:

1) DISTINCT ON . का उपयोग करके :

SELECT DISTINCT ON (mmsi) mmsi 
FROM core_message;

2) RECURSIVE . का उपयोग करना LATERAL के साथ :

WITH RECURSIVE cte AS (
   (
   SELECT mmsi
   FROM   core_message
   ORDER  BY mmsi
   LIMIT  1
   )
   UNION ALL
   SELECT m.*
   FROM   cte c
   CROSS  JOIN LATERAL (
      SELECT mmsi
      FROM   core_message
      WHERE  mmsi > c.mmsi
      ORDER  BY mmsi
      LIMIT  1
      ) m
   )
TABLE cte;

3) LATERAL . के साथ एक अतिरिक्त तालिका का उपयोग करना :

SELECT a.mmsi
FROM test_boats a
CROSS JOIN LATERAL(
    SELECT b.time
    FROM core_message b
    WHERE a.mmsi = b.mmsi
    ORDER BY b.time DESC
    LIMIT 1
) b;

केवल-अनुक्रमणिका स्कैन का उपयोग न करने वाली क्वेरी:

4) DISTINCT ON . का उपयोग करके mmsi,time DESC . के साथ INDEX :

SELECT DISTINCT ON (mmsi) * 
FROM core_message 
ORDER BY mmsi, time desc;

5) DISTINCT ON . का उपयोग करके पिछड़े mmsi,time . के साथ UNIQUE CONSTRAINT :

SELECT DISTINCT ON (mmsi) * 
FROM core_message 
ORDER BY mmsi desc, time desc;

6) RECURSIVE . का उपयोग करना LATERAL के साथ और mmsi,time DESC INDEX :

WITH RECURSIVE cte AS (
   (
   SELECT *
   FROM   core_message
   ORDER  BY mmsi , time DESC 
   LIMIT  1
   )
   UNION ALL
   SELECT m.*
   FROM   cte c
   CROSS  JOIN LATERAL (
      SELECT *
      FROM   core_message
      WHERE  mmsi > c.mmsi
      ORDER  BY mmsi , time DESC 
      LIMIT  1
      ) m
   )
TABLE cte;

7) RECURSIVE . का उपयोग करके LATERAL के साथ और पिछड़ा mmsi,time UNIQUE CONSTRAINT :

WITH RECURSIVE cte AS (

   (

   SELECT *
   FROM   core_message
   ORDER  BY mmsi DESC , time DESC 
   LIMIT  1
   )
   UNION ALL
   SELECT m.*
   FROM   cte c
   CROSS  JOIN LATERAL (
      SELECT *
      FROM   core_message
      WHERE  mmsi < c.mmsi
      ORDER  BY mmsi DESC , time DESC 
      LIMIT  1
      ) m
   )
TABLE cte;

8) LATERAL . के साथ एक अतिरिक्त तालिका का उपयोग करना :

SELECT b.*
FROM test_boats a
CROSS JOIN LATERAL(
    SELECT b.*
    FROM core_message b
    WHERE a.mmsi = b.mmsi
    ORDER BY b.time DESC
    LIMIT 1
) b;

अंतिम संदेश के लिए एक समर्पित तालिका का उपयोग करना:

9) यहाँ मेरा प्रारंभिक समाधान है, केवल अंतिम संदेश के साथ एक विशिष्ट तालिका का उपयोग करना। जैसे ही नए संदेश आते हैं, यह तालिका भर जाती है, लेकिन इसे इस तरह भी बनाया जा सकता है:

CREATE TABLE core_shipinfos AS (
    WITH RECURSIVE cte AS (
       (
       SELECT *
       FROM   core_message
       ORDER  BY mmsi DESC , time DESC 
       LIMIT  1
       )
       UNION ALL
       SELECT m.*
       FROM   cte c
       CROSS  JOIN LATERAL (
          SELECT *
          FROM   core_message
          WHERE  mmsi < c.mmsi
          ORDER  BY mmsi DESC , time DESC 
          LIMIT  1
          ) m
       )
    TABLE cte);

फिर नवीनतम संदेश प्राप्त करने का अनुरोध उतना ही सरल है:

SELECT * FROM core_shipinfos;

परिणाम :

एकाधिक क्वेरी का औसत (तेज़ के लिए लगभग 5):

1) 9146 एमएस
2) 728 एमएस
3) 498 एमएस

4) 51488 एमएस
5) 54764 एमएस
6) 729 एमएस
7) 778 एमएस
8) 516 एमएस

9) 15 एमएस

निष्कर्ष:

मैं समर्पित टेबल समाधान पर टिप्पणी नहीं करूंगा, और इसे अंत तक रखूंगा।

अतिरिक्त तालिका (test_boats ) समाधान निश्चित रूप से यहां विजेता है लेकिन RECURSIVE समाधान भी काफी कुशल है।

DISTINCT ON . के प्रदर्शन में बहुत बड़ा अंतर है केवल-इंडेक्स स्कैन का उपयोग करना और जो इसका उपयोग नहीं कर रहा है, अन्य कुशल क्वेरी के लिए प्रदर्शन लाभ अपेक्षाकृत छोटा है।

यह समझ में आता है क्योंकि उन प्रश्नों में बड़ा सुधार यह तथ्य है कि उन्हें संपूर्ण core_message पर लूप करने की आवश्यकता नहीं है तालिका लेकिन केवल अद्वितीय mmsi . के सबसेट पर जो core_message . की तुलना में काफ़ी छोटा (60K+) है टेबल का आकार (10M+)

एक अतिरिक्त नोट के रूप में, UNIQUE CONSTRAINT का उपयोग करके क्वेरी के प्रदर्शन में कोई उल्लेखनीय सुधार नहीं दिखता है। अगर मैं mmsi,time DESC . छोड़ दूं INDEX . लेकिन उस अनुक्रमणिका को छोड़ने से निश्चित रूप से मुझे कुछ स्थान की बचत होगी (यह अनुक्रमणिका वर्तमान में 328MB लेती है)

समर्पित तालिका समाधान के बारे में:

प्रत्येक संदेश core_message . में संग्रहीत होता है तालिका में स्थितिगत जानकारी (स्थिति, गति, शीर्षक, आदि) और जहाज की जानकारी (नाम, कॉलसाइन, आयाम, आदि), साथ ही जहाज पहचानकर्ता (एमएमएसआई) दोनों होते हैं।

मैं वास्तव में जो करने की कोशिश कर रहा हूं उस पर कुछ और पृष्ठभूमि देने के लिए:मैं जहाजों द्वारा उत्सर्जित संदेशों को AIS प्रोटोकॉल

जैसे, मुझे जो भी अनोखा एमएसआई मिला, वह मुझे इस प्रोटोकॉल के माध्यम से मिला। यह पूर्व-निर्धारित सूची नहीं है। यह नए MMSI को तब तक जोड़ता रहता है जब तक मुझे AIS का उपयोग करके दुनिया के हर जहाज नहीं मिल जाते।

उस संदर्भ में, अंतिम संदेश के रूप में जहाज की जानकारी के साथ एक समर्पित तालिका समझ में आती है।

जैसा कि हमने RECURSIVE . के साथ देखा है, मैं ऐसी तालिका का उपयोग करने से बच सकता हूं समाधान, लेकिन... एक समर्पित तालिका अभी भी इस RECURSIVE . से 50x तेज है समाधान।

वह समर्पित तालिका वास्तव में test_boat . के समान है तालिका, केवल mmsi . से अधिक जानकारी के साथ खेत। वैसे भी, mmsi . के साथ एक टेबल होना core_message . की हर अंतिम जानकारी के साथ केवल फ़ील्ड या तालिका तालिका मेरे आवेदन में समान जटिलता जोड़ें।

अंत में, मुझे लगता है कि मैं इस समर्पित तालिका के लिए जाऊंगा। यह मुझे अपराजेय गति प्रदान करेगा और मेरे पास अभी भी LATERAL का उपयोग करने की संभावना होगी core_message . पर ट्रिक , जो मुझे और अधिक लचीलापन देगा।



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL:डेटाबेस बैकअप और रिकवरी?

  2. JDBCTemplate BeanPropertyRowMapper के साथ नेस्टेड POJO सेट करें

  3. SQLServer के NoLock संकेत के PostgreSQL समतुल्य

  4. मैं JSON Postgres फ़ील्ड की तुलना में कम, अधिक कैसे कर सकता हूँ?

  5. पोस्टग्रेज JDBC ड्राइवर:PSQLException:रिटर्निंग पर या उसके पास सिंटैक्स त्रुटि