PostgreSQL - ดึงแถวที่มีค่าสูงสุดสำหรับคอลัมน์


102

ฉันกำลังจัดการกับตาราง Postgres (เรียกว่า "ชีวิต") ที่มีระเบียนที่มีคอลัมน์สำหรับ time_stamp, usr_id, transaction_id และ lives_remaining ฉันต้องการคำค้นหาที่จะให้ผลรวม life_remaining ล่าสุดสำหรับ usr_id แต่ละรายการ

  1. มีผู้ใช้หลายคน (usr_id ต่างกัน)
  2. time_stamp ไม่ใช่ตัวระบุที่ไม่ซ้ำกัน: บางครั้งเหตุการณ์ของผู้ใช้ (ทีละแถวในตาราง) จะเกิดขึ้นพร้อมกับ time_stamp เดียวกัน
  3. trans_id จะไม่ซ้ำกันสำหรับช่วงเวลาที่เล็กมากเท่านั้น: เมื่อเวลาผ่านไปจะเกิดซ้ำ
  4. ส่วนที่เหลือ (สำหรับผู้ใช้ที่ระบุ) สามารถเพิ่มและลดได้เมื่อเวลาผ่านไป

ตัวอย่าง:

time_stamp | lives_remaining | usr_id | trans_id
-----------------------------------------
  07:00 | 1 | 1 | 1    
  09:00 | 4 | 2 | 2    
  10:00 | 2 | 3 | 3    
  10:00 | 1 | 2 | 4    
  11:00 | 4 | 1 | 5    
  11:00 | 3 | 1 | 6    
  13:00 | 3 | 3 | 1    

เนื่องจากฉันจะต้องเข้าถึงคอลัมน์อื่น ๆ ของแถวพร้อมข้อมูลล่าสุดสำหรับแต่ละ usr_id ที่กำหนดฉันต้องการแบบสอบถามที่ให้ผลลัพธ์ดังนี้:

time_stamp | lives_remaining | usr_id | trans_id
-----------------------------------------
  11:00 | 3 | 1 | 6    
  10:00 | 1 | 2 | 4    
  13:00 | 3 | 3 | 1    

ดังที่ได้กล่าวไว้ usr_id แต่ละรายการสามารถได้รับหรือเสียชีวิตและบางครั้งเหตุการณ์ที่ประทับเวลาเหล่านี้เกิดขึ้นใกล้กันมากจนมีการประทับเวลาเดียวกัน! ดังนั้นการสืบค้นนี้จะใช้ไม่ได้:

SELECT b.time_stamp,b.lives_remaining,b.usr_id,b.trans_id FROM 
      (SELECT usr_id, max(time_stamp) AS max_timestamp 
       FROM lives GROUP BY usr_id ORDER BY usr_id) a 
JOIN lives b ON a.max_timestamp = b.time_stamp

แต่ฉันต้องใช้ทั้ง time_stamp (ครั้งแรก) และ trans_id (วินาที) เพื่อระบุแถวที่ถูกต้อง จากนั้นฉันต้องส่งข้อมูลนั้นจากแบบสอบถามย่อยไปยังแบบสอบถามหลักซึ่งจะให้ข้อมูลสำหรับคอลัมน์อื่น ๆ ของแถวที่เหมาะสม นี่คือข้อความค้นหาที่ถูกแฮ็กที่ฉันได้รับ:

SELECT b.time_stamp,b.lives_remaining,b.usr_id,b.trans_id FROM 
      (SELECT usr_id, max(time_stamp || '*' || trans_id) 
       AS max_timestamp_transid
       FROM lives GROUP BY usr_id ORDER BY usr_id) a 
JOIN lives b ON a.max_timestamp_transid = b.time_stamp || '*' || b.trans_id 
ORDER BY b.usr_id

โอเคมันใช้ได้ แต่ฉันไม่ชอบ มันต้องมีการสืบค้นภายในแบบสอบถามการเข้าร่วมด้วยตนเองและสำหรับฉันแล้วดูเหมือนว่ามันอาจจะง่ายกว่ามากโดยการจับแถวที่ MAX พบว่ามีการประทับเวลาและ trans_id ที่ใหญ่ที่สุด ตาราง "ชีวิต" มีแถวให้แยกวิเคราะห์หลายสิบล้านแถวดังนั้นฉันจึงอยากให้คำค้นหานี้รวดเร็วและมีประสิทธิภาพมากที่สุด ฉันเพิ่งเริ่มใช้ RDBM และ Postgres โดยเฉพาะดังนั้นฉันจึงรู้ว่าฉันต้องใช้ดัชนีที่เหมาะสมอย่างมีประสิทธิภาพ ฉันหลงทางเล็กน้อยเกี่ยวกับวิธีการเพิ่มประสิทธิภาพ

ผมพบว่าการอภิปรายที่คล้ายกันที่นี่ ฉันสามารถใช้ Postgres บางประเภทที่เทียบเท่ากับฟังก์ชันการวิเคราะห์ของ Oracle ได้หรือไม่

คำแนะนำใด ๆ ในการเข้าถึงข้อมูลคอลัมน์ที่เกี่ยวข้องที่ใช้โดยฟังก์ชันรวม (เช่น MAX) การสร้างดัชนีและการสร้างแบบสอบถามที่ดีขึ้นจะได้รับการชื่นชมมาก!

ป.ล. คุณสามารถใช้สิ่งต่อไปนี้เพื่อสร้างกรณีตัวอย่างของฉัน:

create TABLE lives (time_stamp timestamp, lives_remaining integer, 
                    usr_id integer, trans_id integer);
insert into lives values ('2000-01-01 07:00', 1, 1, 1);
insert into lives values ('2000-01-01 09:00', 4, 2, 2);
insert into lives values ('2000-01-01 10:00', 2, 3, 3);
insert into lives values ('2000-01-01 10:00', 1, 2, 4);
insert into lives values ('2000-01-01 11:00', 4, 1, 5);
insert into lives values ('2000-01-01 11:00', 3, 1, 6);
insert into lives values ('2000-01-01 13:00', 3, 3, 1);

Josh คุณอาจไม่ชอบความจริงที่ว่าการเข้าร่วมการสืบค้นด้วยตนเองเป็นต้น แต่ก็ไม่เป็นไรเท่าที่เกี่ยวข้องกับ RDBMS
ลาด

1
สิ่งที่การเข้าร่วมด้วยตนเองจะลงเอยด้วยการแปลคือการแมปดัชนีอย่างง่ายโดยที่ SELECT ด้านใน (อันที่มี MAX) จะสแกนดัชนีที่ทิ้งรายการที่ไม่เกี่ยวข้องออกไปและโดยที่ SELECT ด้านนอกจะจับเฉพาะส่วนที่เหลือของคอลัมน์จากตาราง สอดคล้องกับดัชนีที่แคบลง
vladr

วลาดขอบคุณสำหรับคำแนะนำและคำอธิบาย ฉันเปิดตาฉันถึงวิธีเริ่มทำความเข้าใจการทำงานภายในของฐานข้อมูลและวิธีเพิ่มประสิทธิภาพการสืบค้น Quassnoi ขอบคุณสำหรับข้อความค้นหาที่ยอดเยี่ยมและคำแนะนำเกี่ยวกับคีย์หลัก ออกบิลด้วย. เป็นประโยชน์มาก
Joshua Berry

ขอบคุณที่แสดงวิธีรับMAX BY2 คอลัมน์!

คำตอบ:


95

บนโต๊ะที่มีแถวสุ่มหลอก 158k (usr_id กระจายสม่ำเสมอระหว่าง 0 ถึง 10k trans_idกระจายสม่ำเสมอระหว่าง 0 ถึง 30)

ตามค่าใช้จ่ายในการสืบค้นด้านล่างนี้ฉันกำลังอ้างถึงการประมาณค่าใช้จ่ายของเครื่องมือเพิ่มประสิทธิภาพตามต้นทุนของ Postgres (พร้อมค่าเริ่มต้นของ Postgres xxx_cost) ซึ่งเป็นการประมาณฟังก์ชันการชั่งน้ำหนักของทรัพยากร I / O และ CPU ที่ต้องการ คุณสามารถรับสิ่งนี้ได้โดยเริ่มต้น PgAdminIII และเรียกใช้ "Query / Explain (F7)" บนแบบสอบถามโดยตั้งค่า "Query / Explain options" เป็น "Analyze"

  • แบบสอบถาม Quassnoy มีประมาณการค่าใช้จ่ายของ 745k (!) และเสร็จสมบูรณ์ใน 1.3 วินาที (รับดัชนีสารประกอบบน ( usr_id, trans_id, time_stamp))
  • แบบสอบถามของ Bill มีค่าใช้จ่ายโดยประมาณ 93k และเสร็จสิ้นใน 2.9 วินาที (ให้ดัชนีผสมใน ( usr_id, trans_id))
  • แบบสอบถาม # 1 ด้านล่างมีประมาณการค่าใช้จ่ายของ 16k และเสร็จสมบูรณ์ใน 800ms (รับดัชนีสารประกอบบน ( usr_id, trans_id, time_stamp))
  • แบบสอบถาม # 2 ด้านล่างมีประมาณการค่าใช้จ่ายของ 14k และเสร็จสมบูรณ์ใน 800ms (รับดัชนีฟังก์ชั่นสารประกอบบน ( usr_id, EXTRACT(EPOCH FROM time_stamp), trans_id))
    • นี่คือ Postgres โดยเฉพาะ
  • แบบสอบถาม # 3 ด้านล่าง (Postgres 8.4+) มีประมาณการค่าใช้จ่ายและเสร็จสิ้นเวลาเปรียบได้กับ (หรือดีกว่า) แบบสอบถาม # 2 (รับดัชนีสารประกอบบน ( usr_id, time_stamp, trans_id)); มีข้อดีในการสแกนlivesตารางเพียงครั้งเดียวและหากคุณเพิ่มwork_memชั่วคราว (ถ้าจำเป็น) เพื่อรองรับการจัดเรียงในหน่วยความจำมันจะเร็วที่สุดในการค้นหาทั้งหมด

เวลาทั้งหมดข้างต้นรวมถึงการดึงชุดผลลัพธ์ 10k แถวแบบเต็ม

เป้าหมายของคุณคือการประมาณค่าใช้จ่ายขั้นต่ำและเวลาดำเนินการสืบค้นขั้นต่ำโดยเน้นที่ค่าใช้จ่ายโดยประมาณ การดำเนินการค้นหาอาจขึ้นอยู่กับเงื่อนไขรันไทม์อย่างมีนัยสำคัญ (เช่นแถวที่เกี่ยวข้องถูกแคชไว้ในหน่วยความจำครบถ้วนแล้วหรือไม่) ในขณะที่ค่าใช้จ่ายไม่ประมาณ ในทางกลับกันโปรดทราบว่าการประมาณการต้นทุนนั้นเป็นค่าประมาณ

เวลาในการดำเนินการสืบค้นที่ดีที่สุดจะได้รับเมื่อทำงานบนฐานข้อมูลเฉพาะโดยไม่ต้องโหลด (เช่นการเล่นด้วย pgAdminIII บนพีซีสำหรับการพัฒนา) เวลาในการสืบค้นจะแตกต่างกันไปในการผลิตตามการแพร่กระจายของโหลด / การเข้าถึงข้อมูลของเครื่องจริง เมื่อข้อความค้นหาหนึ่งปรากฏเร็วกว่าอีกเล็กน้อย (<20%) แต่มีค่าใช้จ่ายสูงกว่ามากโดยทั่วไปจะเป็นการดีกว่าที่จะเลือกคำค้นหาที่มีเวลาดำเนินการสูงกว่า แต่มีต้นทุนต่ำกว่า

เมื่อคุณคาดหวังว่าจะไม่มีการแข่งขันสำหรับหน่วยความจำบนเครื่องการผลิตของคุณในขณะที่เรียกใช้แบบสอบถาม (เช่นแคช RDBMS และแคชของระบบไฟล์จะไม่ถูกบีบอัดด้วยการสืบค้นพร้อมกันและ / หรือกิจกรรมของระบบไฟล์) จากนั้นเวลาสืบค้นที่คุณได้รับ ในโหมดสแตนด์อโลน (เช่น pgAdminIII บนพีซีสำหรับพัฒนา) จะเป็นตัวแทน หากมีข้อขัดแย้งในระบบการผลิตเวลาในการสืบค้นจะลดลงตามสัดส่วนกับอัตราส่วนต้นทุนโดยประมาณเนื่องจากแบบสอบถามที่มีต้นทุนต่ำกว่าไม่ต้องพึ่งพาแคชมากนักในขณะที่แบบสอบถามที่มีต้นทุนสูงกว่าจะกลับมาดูข้อมูลเดิมซ้ำแล้วซ้ำเล่า (ทริกเกอร์ I / O เพิ่มเติมในกรณีที่ไม่มีแคชที่เสถียร) เช่น:

              cost | time (dedicated machine) |     time (under load) |
-------------------+--------------------------+-----------------------+
some query A:   5k | (all data cached)  900ms | (less i/o)     1000ms |
some query B:  50k | (all data cached)  900ms | (lots of i/o) 10000ms |

อย่าลืมเรียกใช้ANALYZE livesหนึ่งครั้งหลังจากสร้างดัชนีที่จำเป็นแล้ว


แบบสอบถาม # 1

-- incrementally narrow down the result set via inner joins
--  the CBO may elect to perform one full index scan combined
--  with cascading index lookups, or as hash aggregates terminated
--  by one nested index lookup into lives - on my machine
--  the latter query plan was selected given my memory settings and
--  histogram
SELECT
  l1.*
 FROM
  lives AS l1
 INNER JOIN (
    SELECT
      usr_id,
      MAX(time_stamp) AS time_stamp_max
     FROM
      lives
     GROUP BY
      usr_id
  ) AS l2
 ON
  l1.usr_id     = l2.usr_id AND
  l1.time_stamp = l2.time_stamp_max
 INNER JOIN (
    SELECT
      usr_id,
      time_stamp,
      MAX(trans_id) AS trans_max
     FROM
      lives
     GROUP BY
      usr_id, time_stamp
  ) AS l3
 ON
  l1.usr_id     = l3.usr_id AND
  l1.time_stamp = l3.time_stamp AND
  l1.trans_id   = l3.trans_max

แบบสอบถาม # 2

-- cheat to obtain a max of the (time_stamp, trans_id) tuple in one pass
-- this results in a single table scan and one nested index lookup into lives,
--  by far the least I/O intensive operation even in case of great scarcity
--  of memory (least reliant on cache for the best performance)
SELECT
  l1.*
 FROM
  lives AS l1
 INNER JOIN (
   SELECT
     usr_id,
     MAX(ARRAY[EXTRACT(EPOCH FROM time_stamp),trans_id])
       AS compound_time_stamp
    FROM
     lives
    GROUP BY
     usr_id
  ) AS l2
ON
  l1.usr_id = l2.usr_id AND
  EXTRACT(EPOCH FROM l1.time_stamp) = l2.compound_time_stamp[1] AND
  l1.trans_id = l2.compound_time_stamp[2]

ปรับปรุง 2013/01/29

สุดท้ายสำหรับเวอร์ชัน 8.4 Postgres รองรับฟังก์ชัน Windowซึ่งหมายความว่าคุณสามารถเขียนบางสิ่งที่เรียบง่ายและมีประสิทธิภาพเช่น:

แบบสอบถาม # 3

-- use Window Functions
-- performs a SINGLE scan of the table
SELECT DISTINCT ON (usr_id)
  last_value(time_stamp) OVER wnd,
  last_value(lives_remaining) OVER wnd,
  usr_id,
  last_value(trans_id) OVER wnd
 FROM lives
 WINDOW wnd AS (
   PARTITION BY usr_id ORDER BY time_stamp, trans_id
   ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
 );

โดยดัชนีผสมบน (usr_id, trans_id, times_tamp) คุณหมายถึงคำว่า "CREATE INDEX lives_blah_idx ON lives (usr_id, trans_id, time_stamp)" หรือไม่ หรือฉันควรสร้างดัชนีแยกกันสามรายการสำหรับแต่ละคอลัมน์ ฉันควรยึดตามค่าเริ่มต้นของ "การใช้ต้นไม้" ใช่ไหม
Joshua Berry

1
ใช่สำหรับตัวเลือกแรก: ฉันหมายถึง CREATE INDEX lives_blah_idx ON lives (usr_id, trans_id, time_stamp) :) ไชโย
vladr

ขอบคุณที่แม้แต่ทำการเปรียบเทียบต้นทุน! ตอบโจทย์ครบมาก!
อดัม

@vladr ฉันเพิ่งเจอคำตอบของคุณ ฉันสับสนเล็กน้อยอย่างที่คุณบอกว่าแบบสอบถาม 1 มีค่าใช้จ่าย 16k และแบบสอบถาม 2 ราคา 14k แต่ต่อไปในตารางคุณบอกว่าแบบสอบถาม 1 มีค่าใช้จ่าย 5k และแบบสอบถาม 2 มีค่าใช้จ่าย 50k คำถามใดที่ควรใช้? :) ขอบคุณ
Houman

1
@Kave ตารางนี้มีไว้สำหรับคู่ของแบบสอบถามสมมุติเพื่อแสดงตัวอย่างไม่ใช่คำค้นหาสองคำของ OP การเปลี่ยนชื่อเพื่อลดความสับสน
vladr

88

ฉันจะเสนอเวอร์ชันที่สะอาดตามDISTINCT ON(ดูเอกสาร ):

SELECT DISTINCT ON (usr_id)
    time_stamp,
    lives_remaining,
    usr_id,
    trans_id
FROM lives
ORDER BY usr_id, time_stamp DESC, trans_id DESC;

7
นี่เป็นคำตอบที่สั้นและน่าฟัง ยังมีข้อมูลอ้างอิงที่ดีอีกด้วย! นี่ควรเป็นคำตอบที่ได้รับการยอมรับ
Prakhar Agrawal

สิ่งนี้ดูเหมือนจะใช้ได้ผลกับฉันในแอปพลิเคชันที่แตกต่างกันเล็กน้อยโดยที่ไม่มีอะไรอื่นอีกแล้ว ควรยกขึ้นเพื่อให้มองเห็นได้ชัดเจนขึ้น
Jim Factor

8

นี่เป็นอีกวิธีหนึ่งซึ่งเกิดขึ้นโดยไม่ใช้การสืบค้นย่อยที่สัมพันธ์กันหรือ GROUP BY ฉันไม่เชี่ยวชาญในการปรับแต่งประสิทธิภาพ PostgreSQL ดังนั้นฉันขอแนะนำให้คุณลองทั้งสองอย่างนี้และวิธีแก้ปัญหาที่คนอื่น ๆ มอบให้เพื่อดูว่าตัวไหนดีกว่าสำหรับคุณ

SELECT l1.*
FROM lives l1 LEFT OUTER JOIN lives l2
  ON (l1.usr_id = l2.usr_id AND (l1.time_stamp < l2.time_stamp 
   OR (l1.time_stamp = l2.time_stamp AND l1.trans_id < l2.trans_id)))
WHERE l2.usr_id IS NULL
ORDER BY l1.usr_id;

ฉันกำลังสมมติว่ามีความเป็นเอกลักษณ์อย่างน้อยกว่ามูลค่าใดก็ตามtrans_idtime_stamp


4

ฉันชอบสไตล์คำตอบของMike Woodhouseในหน้าอื่น ๆ ที่คุณกล่าวถึง จะกระชับเป็นพิเศษเมื่อสิ่งที่ถูกขยายให้ใหญ่สุดเป็นเพียงคอลัมน์เดียวซึ่งในกรณีนี้คิวรีย่อยสามารถใช้ได้MAX(some_col)และGROUP BYคอลัมน์อื่น ๆ แต่ในกรณีของคุณคุณมีปริมาณ 2 ส่วนที่จะขยายใหญ่สุดคุณยังสามารถทำได้โดยใช้ORDER BYบวกLIMIT 1แทน (ทำโดย Quassnoi):

SELECT * 
FROM lives outer
WHERE (usr_id, time_stamp, trans_id) IN (
    SELECT usr_id, time_stamp, trans_id
    FROM lives sq
    WHERE sq.usr_id = outer.usr_id
    ORDER BY trans_id, time_stamp
    LIMIT 1
)

ฉันพบว่าการใช้ไวยากรณ์ row-constructor นั้นWHERE (a, b, c) IN (subquery)ดีเพราะมันลดจำนวนคำฟุ่มเฟือยที่จำเป็น


4

Actaully มีวิธีแก้ปัญหาที่แฮ็กสำหรับปัญหานี้ สมมติว่าคุณต้องการเลือกต้นไม้ที่ใหญ่ที่สุดของแต่ละป่าในภูมิภาค

SELECT (array_agg(tree.id ORDER BY tree_size.size)))[1]
FROM tree JOIN forest ON (tree.forest = forest.id)
GROUP BY forest.id

เมื่อคุณจัดกลุ่มต้นไม้ตามป่าไม้จะมีรายการต้นไม้ที่ไม่ได้เรียงลำดับและคุณต้องหาต้นไม้ที่ใหญ่ที่สุด สิ่งแรกที่คุณควรทำคือจัดเรียงแถวตามขนาดและเลือกแถวแรกในรายการของคุณ อาจดูเหมือนไม่มีประสิทธิภาพ แต่ถ้าคุณมีแถวหลายล้านแถวมันจะค่อนข้างเร็วกว่าโซลูชันที่มีJOINของและWHEREเงื่อนไข

BTW โปรดทราบว่าORDER_BYสำหรับarray_aggใช้ใน Postgresql 9.0


คุณมีข้อผิดพลาด คุณต้องเขียน ORDER BY tree_size.size DESC นอกจากนี้สำหรับงานของผู้เขียนรหัสจะมีลักษณะดังนี้ SELECT usr_id, (array_agg(time_stamp ORDER BY time_stamp DESC))[1] AS timestamp, (array_agg(lives_remaining ORDER BY time_stamp DESC))[1] AS lives_remaining, (array_agg(trans_id ORDER BY time_stamp DESC))[1] AS trans_id FROM lives GROUP BY usr_id
alexkovelsky

3

มีตัวเลือกใหม่ใน Postgressql 9.5 ที่เรียกว่า DISTINCT ON

SELECT DISTINCT ON (location) location, time, report
    FROM weather_reports
    ORDER BY location, time DESC;

มันกำจัดแถวที่ซ้ำกันออกจากแถวแรกเท่านั้นตามที่กำหนดคำสั่ง ORDER BY ของฉัน

ดูเอกสารอย่างเป็นทางการ


1
SELECT  l.*
FROM    (
        SELECT DISTINCT usr_id
        FROM   lives
        ) lo, lives l
WHERE   l.ctid = (
        SELECT ctid
        FROM   lives li
        WHERE  li.usr_id = lo.usr_id
        ORDER BY
          time_stamp DESC, trans_id DESC
        LIMIT 1
        )

การสร้างดัชนี(usr_id, time_stamp, trans_id)จะช่วยปรับปรุงแบบสอบถามนี้ได้มาก

คุณควรมีบางอย่างPRIMARY KEYในตารางของคุณเสมอ


0

ฉันคิดว่าคุณมีปัญหาสำคัญอย่างหนึ่งที่นี่: ไม่มี "ตัวนับ" ที่เพิ่มขึ้นซ้ำซากจำเจเพื่อรับประกันว่าแถวหนึ่ง ๆ จะเกิดขึ้นช้ากว่าแถวอื่น ใช้ตัวอย่างนี้:

timestamp   lives_remaining   user_id   trans_id
10:00       4                 3         5
10:00       5                 3         6
10:00       3                 3         1
10:00       2                 3         2

คุณไม่สามารถระบุได้จากข้อมูลนี้ว่ารายการใดเป็นข้อมูลล่าสุด เป็นคนที่สองหรือคนสุดท้าย? ไม่มีฟังก์ชัน sort หรือ max () ที่คุณสามารถใช้กับข้อมูลนี้เพื่อให้คำตอบที่ถูกต้องแก่คุณ

การเพิ่มความละเอียดของการประทับเวลาจะช่วยได้มาก เนื่องจากเอ็นจินฐานข้อมูลทำให้คำขอเป็นอนุกรมด้วยความละเอียดที่เพียงพอคุณจึงสามารถรับประกันได้ว่าจะไม่มีการประทับเวลาสองรายการเหมือนกัน

หรือใช้ trans_id ที่จะไม่พลิกไปมาเป็นเวลานานมาก การมี trans_id ที่เลื่อนทับหมายความว่าคุณไม่สามารถบอกได้ (สำหรับการประทับเวลาเดียวกัน) ว่า trans_id 6 ล่าสุดกว่า trans_id 1 หรือไม่เว้นแต่คุณจะคำนวณทางคณิตศาสตร์ที่ซับซ้อน


ใช่คอลัมน์ลำดับ (การสร้างอัตโนมัติ) จะเป็นไปตามลำดับ
vladr

สมมติฐานจากด้านบนคือสำหรับการเพิ่มครั้งละเล็กน้อย trans_id จะไม่พลิกทับ ฉันยอมรับว่าตารางต้องการดัชนีหลักที่ไม่ซ้ำใคร - เหมือนกับ trans_id ที่ไม่ซ้ำกัน (ป.ล. ดีใจที่ตอนนี้มีคะแนนกรรม / ชื่อเสียงมากพอที่จะแสดงความคิดเห็น!)
Joshua Berry

วลาดระบุว่า trans_id มีรอบที่ค่อนข้างสั้นซึ่งจะหมุนเวียนบ่อย แม้ว่าคุณจะพิจารณาเฉพาะสองแถวกลางจากตารางของฉัน (trans_id = 6 และ 1) คุณก็ยังไม่สามารถบอกได้ว่ารายการใดเป็นข้อมูลล่าสุด ดังนั้นการใช้ max (trans_id) สำหรับการประทับเวลาที่กำหนดจะไม่ได้ผล
Barry Brown

ใช่ฉันอาศัยการรับประกันของผู้เขียนแอปพลิเคชันว่าทูเปิล (time_stamp, trans_id) ไม่ซ้ำกันสำหรับผู้ใช้ที่ระบุ หากไม่เป็นเช่นนั้น "SELECT l1.usr_id, l1.lives_left, ... FROM ... WHERE ... " จะต้องกลายเป็น "SELECT l1.usr_id, MAX / MIN (l1.lives_left), ... FROM .. ที่ไหน ... GROUP BY l1.usr_id, ...
vladr

0

อีกวิธีหนึ่งที่คุณอาจพบว่ามีประโยชน์

SELECT t.*
FROM
    (SELECT
        *,
        ROW_NUMBER() OVER(PARTITION BY usr_id ORDER BY time_stamp DESC) as r
    FROM lives) as t
WHERE t.r = 1
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.