วิธีที่เร็วที่สุดในการนับจำนวนแถวที่แน่นอนในตารางที่มีขนาดใหญ่มาก?


234

ฉันเจอบทความที่แจ้งว่าSELECT COUNT(*) FROM TABLE_NAMEจะช้าเมื่อตารางมีจำนวนแถวและคอลัมน์จำนวนมาก

ฉันมีตารางที่อาจมีหลายพันล้านแถว [มีประมาณ 15 คอลัมน์] มีวิธีที่ดีกว่าในการรับจำนวนที่แน่นอนของจำนวนแถวของตารางหรือไม่

โปรดพิจารณาสิ่งต่อไปนี้ก่อนคำตอบของคุณ:

  • ฉันกำลังมองหาโซลูชันที่เป็นอิสระจากผู้จำหน่ายฐานข้อมูล มันก็โอเคถ้ามันครอบคลุมMySQL , ออราเคิล , MS SQL Server แต่ถ้าไม่มีผู้ให้บริการฐานข้อมูลที่เป็นอิสระจริงๆแล้วฉันจะตัดสินหาคำตอบที่แตกต่างกันสำหรับผู้จำหน่ายฐานข้อมูลที่แตกต่างกัน

  • ฉันไม่สามารถใช้เครื่องมือภายนอกอื่นเพื่อทำสิ่งนี้ ฉันกำลังมองหาโซลูชันที่ยึดตาม SQL เป็นหลัก

  • ฉันไม่สามารถทำให้การออกแบบฐานข้อมูลของฉันเป็นปกติอีกต่อไป มันมีอยู่แล้วใน 3NF และยิ่งกว่านั้นมีการเขียนโค้ดจำนวนมากรอบ ๆ


4
และเพียงแค่อยากรู้ว่าทำไมมันเป็นสิ่งจำเป็นในปริมาณที่ทันทีที่แน่นอนของแถวเมื่อคุณมีพันล้านของพวกเขา ...
zerkms

2
เราทุกคนจะไม่หวังว่าโครงสร้างเฉพาะนี้ได้รับการปรับให้เหมาะสมโดยผู้จำหน่ายฐานข้อมูลของเราหรือไม่
KevinDTimm

5
@Swaranga คุณสามารถอธิบายเพิ่มเติมเล็กน้อยเกี่ยวกับวัตถุประสงค์ในการบำรุงรักษาฐานข้อมูลนี้ที่ต้องรู้จำนวนแถวที่แน่นอนในตารางหรือไม่ ฉันนึกภาพไม่ออก และในขณะที่เควินกล่าวว่าถ้ามีวิธีที่เร็วกว่า COUNT (*) แล้วผู้ขายจะ DBMS (ควร) แน่นอนอีกครั้งใช้ COUNT (*) ที่จะใช้มัน ...
โทนี่แอนดรู

3
แน่นอนถ้าตารางถูกเขียนไปยังบ่อยครั้งการนับจำนวนที่แน่นอนของคุณจะถูกต้องสำหรับเวลาเฉพาะและอาจไม่ถูกต้องหากกระบวนการอื่นเขียนลงในตารางเว้นแต่คุณจะใส่การล็อคตารางลงในแบบสอบถาม
Steve Ford

2
คุณสามารถใช้ตัวแทรกและลบทริกเกอร์เพื่อให้มีการนับหรือไม่
paparazzo

คำตอบ:


246

คำตอบง่ายๆ:

  • โซลูชันอิสระของผู้จำหน่ายฐานข้อมูล = ใช้มาตรฐาน = COUNT(*)
  • มีโซลูชัน SQL Server โดยประมาณแต่ไม่ใช้ COUNT (*) = ไม่อยู่ในขอบเขต

หมายเหตุ:

COUNT (1) = COUNT (*) = COUNT (PrimaryKey)ในกรณี

แก้ไข:

ตัวอย่าง SQL Server (1.4 พันล้านแถว, 12 คอลัมน์)

SELECT COUNT(*) FROM MyBigtable WITH (NOLOCK)
-- NOLOCK here is for me only to let me test for this answer: no more, no less

1 การวิ่ง, 5:46 นาที, นับ = 1,401,659,700

--Note, sp_spaceused uses this DMV
SELECT
   Total_Rows= SUM(st.row_count)
FROM
   sys.dm_db_partition_stats st
WHERE
    object_name(object_id) = 'MyBigtable' AND (index_id < 2)

2 วิ่งทั้งน้อยกว่า 1 วินาทีนับ = 1,401,659,670

แถวที่สองมีจำนวนแถวน้อยกว่า = ผิด จะเหมือนกันหรือมากกว่านั้นขึ้นอยู่กับการเขียน (การลบเสร็จสิ้นในชั่วโมงนี้)


9
COUNT(*) = COUNT(key)Nope, นี่เป็นเพียงความผิด หากไม่มีNOT NULLข้อ จำกัด - พวกเขาจะไม่เท่ากัน (ในผลลัพธ์เช่นเดียวกับในแผนปฏิบัติการ)
zerkms

14
@zerkmsby: สำหรับ COUNT (คีย์) ฉันหมายถึง COUNT (คีย์หลัก) ซึ่งไม่ควรเป็นโมฆะ ฉันจะอธิบาย
gbn

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

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

5
@gbn โซลูชันที่ดีมากคุณสามารถบอกได้ว่าใช้index_id < 2อะไร
มอบ

29

วิธีที่เร็วที่สุดบน MySQL คือ:

SHOW TABLE STATUS;

คุณจะได้รับตารางทั้งหมดทันทีด้วยการนับแถว (ซึ่งเป็นผลรวม) พร้อมด้วยข้อมูลเพิ่มเติมมากมายหากคุณต้องการ


1
วิธีที่ชาญฉลาด .. ด้วยสิ่งนี้คุณสามารถรับจำนวนแถวของหลายตารางใน 1 คิวรี
Deval Khandelwal

คุณรันบน db ที่มีตารางที่มี ~ billion รายการเช่น @gbn และสังเกตเวลาหรือไม่?
KNU

ค่าใดคือจำนวนแถวทั้งหมดสำหรับตารางทั้งหมดในฐานข้อมูล และนี่คือค่าประมาณ - ถ้าคุณต้องการค่าการนับแถวที่แน่นอน
Kreeverp

2
สิ่งนี้ไม่ได้ผลเลยตัวอย่างเช่น INNODB เอ็นจิ้นการจัดเก็บอ่านสองสามแถวและคาดเดาจำนวนแถว
Martijn Scheffer

10

ฉันเจอบทความที่ระบุว่า COUNT (*) จาก TABLE_NAME จะช้าเมื่อตารางมีจำนวนแถวและคอลัมน์จำนวนมาก

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

โปรดทราบว่าโดยทั่วไปคุณสามารถแยกการประมาณที่ดีได้โดยใช้เครื่องมือเพิ่มประสิทธิภาพการสืบค้นสถิติตาราง ฯลฯ ในกรณีของ PostgreSQL คุณสามารถแยกวิเคราะห์ผลลัพธ์explain count(*) from yourtableและรับการประมาณจำนวนแถวที่ดี ซึ่งนำฉันไปสู่คำถามที่สองของคุณ

ฉันมีตารางที่อาจมีหลายพันล้านแถว [มีประมาณ 15 คอลัมน์] มีวิธีที่ดีกว่าในการรับจำนวนที่แน่นอนของจำนวนแถวของตารางหรือไม่

อย่างจริงจัง? :-) คุณหมายถึงจำนวนที่แน่นอนจากตารางที่มีพันล้านแถวจริงหรือ คุณแน่ใจเหรอ :-)

หากคุณทำจริง ๆคุณสามารถติดตามผลรวมโดยใช้ทริกเกอร์ แต่โปรดระลึกถึงการทำงานพร้อมกันและการหยุดชะงักหากคุณทำ


ใช่เดนิสต้องการจำนวนที่แน่นอน :(
Swaranga Sarma

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

อย่างน้อยคุณก็เอาใจใส่กับฉัน โซลูชันของ Oracle มีเพียงวิธีเดียวเท่านั้น ที่จะลดปัญหาของฉันในระดับหนึ่ง ปัจจุบันลูกค้าใช้ Oracle; ดังนั้นถ้าฉันมีวิธีแก้ปัญหาเฉพาะสำหรับ Oracle สิ่งนั้นจะทำ [ในขณะนั้น] :)
Swaranga Sarma

6
"ใช่ Denis จำเป็นต้องมีการนับที่แน่นอน :(" - ฉันสามารถคาดเดาได้เท่านั้นกระบวนการบำรุงรักษา db พบว่ามี 42,123,876 แถวในตาราง A แล้วสร้าง 42,123,876 แถวที่ว่างในตาราง B แล้ววนรอบตาราง A และอัปเดตแถวในตาราง B ... หรือไม่หรือมันช่างบ้าคลั่งกว่านั้น? ;-)
Tony Andrews

1
ธุรกรรม 2 ไม่สามารถเริ่มก่อนที่จะมีการทำธุรกรรม 1 หากไม่มีการปรับปรุง "ตารางนับ" ธุรกรรมการอัพเดทจำนวนมากสามารถทำงานในแบบคู่ขนาน ด้วย "ตารางการนับ" แต่ละธุรกรรมจะต้อง "รับตั๋ว" เพื่ออัปเดตการนับ ดังนั้นการทำธุรกรรมเริ่มเข้าคิวที่เครื่องขายตั๋ว (ผู้กำหนดตารางเวลาตัดสินใจว่าใครจะเป็นคนต่อไปที่จะได้รับการล็อคในตารางการนับ)
เออร์วิน Smout

10

มีวิธีที่ดีกว่าในการรับจำนวนที่แน่นอนของจำนวนแถวของตารางหรือไม่

เพื่อตอบคำถามของคุณอย่างง่าย ๆไม่ไม่มี

หากคุณต้องการวิธีการที่เป็นอิสระจาก DBMS ในการทำเช่นนี้วิธีที่เร็วที่สุดคือ:

SELECT COUNT(*) FROM TableName

ผู้ขาย DBMS บางรายอาจมีวิธีที่รวดเร็วกว่าซึ่งจะใช้ได้กับระบบของพวกเขาเท่านั้น ตัวเลือกเหล่านี้บางส่วนถูกโพสต์แล้วในคำตอบอื่น ๆ

COUNT(*) ควรได้รับการปรับให้เหมาะสมโดย DBMS (อย่างน้อยฐานข้อมูลที่มีค่าของ PROD) ดังนั้นอย่าพยายามเลี่ยงการปรับให้เหมาะสม

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


10

ฉันได้รับสคริปต์นี้จากคำถาม / คำตอบ StackOverflow อื่น:

SELECT SUM(p.rows) FROM sys.partitions AS p
  INNER JOIN sys.tables AS t
  ON p.[object_id] = t.[object_id]
  INNER JOIN sys.schemas AS s
  ON s.[schema_id] = t.[schema_id]
  WHERE t.name = N'YourTableNameHere'
  AND s.name = N'dbo'
  AND p.index_id IN (0,1);

ตารางของฉันมี 500 ล้านบันทึกและผลตอบแทนดังกล่าวข้างต้นใช้เวลาน้อยกว่า 1ms ในขณะเดียวกัน,

SELECT COUNT(id) FROM MyTable

ใช้เวลาเต็ม 39 นาที 52 วินาที!

พวกเขาให้จำนวนแถวเท่ากันทั้งหมด (ในกรณีของฉันคือ 519326012)

ฉันไม่ทราบว่าจะเป็นอย่างนั้นเสมอหรือไม่


คุณสามารถเพิ่มพารามิเตอร์เพื่อรับจำนวนแถวด้วยแบบสอบถามนี้ได้หรือไม่? ตัวอย่าง: เลือก COUNT (1) จาก TABLENAME WHERE ColumnFiled = '1' ด้วยข้อความค้นหาของคุณ?
VnDevil

นั่นคือการนับ - จำนวนแถว (บันทึก) คือ "การนับ" ในกรณีนี้ "500 ล้านบันทึก" เป็นตัวเลขโดยประมาณและ "519326012" เป็นจำนวนแถวหรือจำนวนที่แน่นอน แถว = records = count
JakeJ

9

คุณสามารถลองsp_spaceusedนี้(Transact-SQL)

แสดงจำนวนแถวพื้นที่ดิสก์ที่สงวนไว้และพื้นที่ดิสก์ที่ใช้โดยตารางมุมมองที่จัดทำดัชนีหรือคิว Service Broker ในฐานข้อมูลปัจจุบันหรือแสดงพื้นที่ดิสก์ที่สงวนและใช้โดยฐานข้อมูลทั้งหมด


sp_spaceused จะไม่ให้จำนวนฉันโดยประมาณใช่ไหม
Swaranga Sarma

1
FYI: สิ่งนี้ใช้ sys.dm_db_partition_stats ภายใน
gbn

6

หาก SQL Server edition เป็น 2005/2008 คุณสามารถใช้ DMV เพื่อคำนวณจำนวนแถวในตาราง:

-- Shows all user tables and row counts for the current database 
-- Remove is_ms_shipped = 0 check to include system objects 
-- i.index_id < 2 indicates clustered index (1) or hash table (0) 
SELECT o.name, 
 ddps.row_count 
FROM sys.indexes AS i 
 INNER JOIN sys.objects AS o ON i.OBJECT_ID = o.OBJECT_ID 
 INNER JOIN sys.dm_db_partition_stats AS ddps ON i.OBJECT_ID = ddps.OBJECT_ID 
 AND i.index_id = ddps.index_id 
WHERE i.index_id < 2 
 AND o.is_ms_shipped = 0 
ORDER BY o.NAME 

สำหรับโปรแกรมฐานข้อมูล SQL Server 2000, sysindexes จะทำงานได้ แต่ขอแนะนำอย่างยิ่งให้หลีกเลี่ยงการใช้ใน SQL Server รุ่นต่อไปในอนาคตเนื่องจากอาจถูกลบออกในอนาคตอันใกล้

โค้ดตัวอย่างที่นำมาจาก: วิธีการรับจำนวนแถวของตารางนับอย่างรวดเร็วและไม่เจ็บปวด


นี่คือตัวอย่างไม่แน่นอน : เห็นคำตอบของฉันโปรด
GBN

คุณรู้ตัวอย่างที่สิ่งนี้ไม่ถูกต้องหรือไม่? AFAIK ไม่ได้ขึ้นอยู่กับสถิติที่อัพเดท
Alireza Maddah


5

ฉันไม่มีผู้เชี่ยวชาญใกล้เคียงกับคนอื่น ๆ ที่ได้รับคำตอบ แต่ฉันมีปัญหากับขั้นตอนที่ฉันใช้เพื่อเลือกแถวแบบสุ่มจากตาราง (ไม่เกี่ยวข้องมากเกินไป) แต่ฉันจำเป็นต้องทราบจำนวนแถวในตารางอ้างอิงของฉัน เพื่อคำนวณดัชนีสุ่ม ใช้งาน Count (*) หรือ Count (1) แบบเดิม แต่บางครั้งฉันก็ใช้งานได้ถึง 2 วินาทีเพื่อให้การค้นหาของฉันทำงาน ดังนั้นแทน (สำหรับตารางของฉันชื่อ 'tbl_HighOrder') ฉันกำลังใช้:

Declare @max int

Select @max = Row_Count
From sys.dm_db_partition_stats
Where Object_Name(Object_Id) = 'tbl_HighOrder'

มันใช้งานได้ดีและเวลาสอบถามใน Management Studio นั้นเป็นศูนย์


1
FWIW คุณควรพูดถึงผู้ขายฐานข้อมูลที่คุณใช้อยู่ ฉันคิดว่าคำสั่งจะแตกต่างกันเล็กน้อยขึ้นอยู่กับผู้ขาย
ToolmakerSteve

5

ดีปลาย 5 ปีและไม่แน่ใจว่าจะช่วย:

ฉันพยายามนับเลข แถวในตาราง SQL Server โดยใช้MS SQL Server Management Studioและพบข้อผิดพลาดล้นบางส่วนจากนั้นฉันใช้ด้านล่าง:

เลือกcount_big (1) จาก [dbname]. [dbo]. [FactSampleValue];

ผลลัพธ์ :

24296650578 แถว


5

ฉันพบบทความที่ดีนี้ของSQL Server - HOW-TO: ดึงจำนวนแถวที่ถูกต้องอย่างรวดเร็วสำหรับตารางจากmartijnh1ซึ่งจะช่วยให้สรุปที่ดีสำหรับแต่ละสถานการณ์

ฉันต้องการสิ่งนี้เพื่อขยายที่ฉันต้องการให้การนับตามเงื่อนไขที่เฉพาะเจาะจงและเมื่อฉันคิดส่วนนี้ฉันจะอัปเดตคำตอบนี้เพิ่มเติม

ในระหว่างนี้นี่คือรายละเอียดจากบทความ:

วิธีที่ 1:

ค้นหา:

SELECT COUNT(*) FROM Transactions 

ความคิดเห็นที่:

ทำการสแกนแบบเต็มตาราง ช้าลงบนโต๊ะขนาดใหญ่

วิธีที่ 2:

ค้นหา:

SELECT CONVERT(bigint, rows) 
FROM sysindexes 
WHERE id = OBJECT_ID('Transactions') 
AND indid < 2 

ความคิดเห็นที่:

วิธีที่รวดเร็วในการดึงข้อมูลการนับแถว ขึ้นอยู่กับสถิติและไม่ถูกต้อง

เรียกใช้การปรับปรุง DBCC (ฐานข้อมูล) ด้วย COUNT_ROWS ซึ่งอาจใช้เวลามากสำหรับตารางขนาดใหญ่

วิธีที่ 3:

ค้นหา:

SELECT CAST(p.rows AS float) 
FROM sys.tables AS tbl 
INNER JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id and
idx.index_id < 2 
INNER JOIN sys.partitions AS p ON p.object_id=CAST(tbl.object_id AS int) 
AND p.index_id=idx.index_id 
WHERE ((tbl.name=N'Transactions' 
AND SCHEMA_NAME(tbl.schema_id)='dbo')) 

ความคิดเห็นที่:

วิธีที่ Studio การจัดการ SQL นับแถว (ดูที่คุณสมบัติของตารางที่เก็บข้อมูลการนับแถว) เร็วมาก แต่ยังคงเป็นจำนวนแถวโดยประมาณ

วิธีที่ 4:

ค้นหา:

SELECT SUM (row_count) 
FROM sys.dm_db_partition_stats 
WHERE object_id=OBJECT_ID('Transactions')    
AND (index_id=0 or index_id=1); 

ความคิดเห็นที่:

การดำเนินการด่วน (แม้ว่าจะไม่เร็วเท่าวิธีที่ 2) และมีความสำคัญเท่าเทียมกันและเชื่อถือได้


ขอบคุณ! เคล็ดลับที่มีประโยชน์จริงๆ ฉันไม่ได้รับอนุญาตให้ดูตารางระบบดังนั้นวิธีที่ 4 ไม่ใช่ฉัน อย่างไรก็ตามวิธีที่ 3 ดีพอ
นิโคลัส Humphrey

3

ฉันไม่คิดว่าจะมีวิธีแก้ปัญหาที่เร็วที่สุดเสมอโดยทั่วไป: RDBMS / เวอร์ชั่นบางรุ่นมีการเพิ่มประสิทธิภาพเฉพาะสำหรับการSELECT COUNT(*)ใช้ตัวเลือกที่เร็วขึ้นในขณะที่คนอื่นเพียงแค่สแกนตาราง คุณจะต้องไปที่เว็บไซต์เอกสาร / การสนับสนุนสำหรับชุดที่สองซึ่งอาจจะต้องมีการเขียนแบบสอบถามที่เฉพาะเจาะจงมากขึ้นโดยทั่วไปจะเป็นแบบสอบถามที่นิยมดัชนีในบางวิธี

แก้ไข:

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


ฉันจะหวังมากว่า DBMS ดีใด ๆ SELECT COUNT(*)ที่จะใช้ดัชนีสำหรับ แม้แต่ MySQL ก็ทำอย่างนั้น ...
sleske

สมมติว่าการลบไม่เกิดขึ้น - อย่างจริงจัง ?? ; p
ToolmakerSteve

3

ฉันมาสายคำถามนี้ แต่นี่คือสิ่งที่คุณสามารถทำกับ MySQL (เมื่อฉันใช้ MySQL) ฉันกำลังแบ่งปันข้อสังเกตของฉันที่นี่:

1) SELECT COUNT(*) AS TOTAL_ROWS FROM <TABLE_NAME>


จำนวนแถวผลลัพธ์ : 508534
เอาต์พุตคอนโซล: แถวที่ได้รับผลกระทบ: 0 แถวพบ: 1 คำเตือน: 0 ระยะเวลาสำหรับ 1 ข้อความค้นหา: 0.125 วินาที
ใช้เวลาสักครู่สำหรับตารางที่มีจำนวนแถวมาก แต่การนับแถวนั้นแน่นอนมาก

2) SHOW TABLE STATUS or SHOW TABLE STATUS WHERE NAME="<TABLE_NAME>"


จำนวนแถวผลลัพธ์ : 511235
เอาต์พุตคอนโซล: แถวที่ได้รับผลกระทบ: 0 แถวพบ: 1 คำเตือน: 0 ระยะเวลาสำหรับ 1 ข้อความค้นหา: 0.250 วินาทีสรุป: จำนวนแถวไม่แน่นอน

3) SELECT * FROM information_schema.tables WHERE table_schema = DATABASE();

ผลลัพธ์
จำนวนแถว: 507806
เอาต์พุตคอนโซล: แถวที่ได้รับผลกระทบ: 0 แถวพบ: 48 คำเตือน: 0 ระยะเวลาสำหรับ 1 ข้อความค้นหา: 1.701 วินาที
การนับแถวไม่ถูกต้อง

ฉันไม่ใช่ผู้เชี่ยวชาญด้าน MySQL หรือฐานข้อมูล แต่ฉันพบว่าสำหรับตารางที่มีขนาดใหญ่มากคุณสามารถใช้ตัวเลือกที่ 2 หรือ 3 และได้รับ 'แนวคิดที่เป็นธรรม' ของจำนวนแถวที่มีอยู่

ฉันต้องการรับจำนวนแถวเหล่านี้เพื่อแสดงสถิติบางอย่างบน UI ด้วยการค้นหาข้างต้นฉันรู้ว่าแถวทั้งหมดมีมากกว่า 500,000 ดังนั้นฉันจึงแสดงสถิติเช่น "มากกว่า 500,000 แถว" โดยไม่แสดงจำนวนแถวที่แน่นอน

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


2

ไม่ใช่โซลูชันที่ไม่เชื่อเรื่องพระเจ้าของ DBMS แต่อย่างน้อยรหัสลูกค้าของคุณจะไม่เห็นความแตกต่าง ...

สร้างตาราง T อีกอันโดยมีเพียงหนึ่งแถวและจำนวนเต็มหนึ่งฟิลด์ N 1และสร้าง INSERT TRIGGER ที่เพิ่งดำเนินการ:

UPDATE T SET N = N + 1

สร้างทริกเกอร์ DELETE ที่ทำงานด้วย:

UPDATE T SET N = N - 1

DBMS ที่คุ้มค่ากับเกลือจะรับประกันว่าอะตอมมิกของการดำเนินการด้านบน2และ N จะมีจำนวนแถวที่ถูกต้องตลอดเวลาซึ่งเป็นวิธีที่รวดเร็วมากในการรับ:

SELECT N FROM T

ในขณะที่ทริกเกอร์เป็นเฉพาะ DBMS การเลือกจาก T ไม่ใช่และรหัสลูกค้าของคุณไม่จำเป็นต้องเปลี่ยนสำหรับ DBMS ที่รองรับแต่ละรายการ

อย่างไรก็ตามสิ่งนี้อาจมีปัญหาเรื่องความสามารถในการปรับขนาดได้หากตาราง INSERT หรือ DELETE-เร่งรัด


1ชื่อเหล่านี้เป็นเพียงตัวยึดตำแหน่ง - ใช้สิ่งที่มีความหมายมากขึ้นในการผลิต

2 Ie N ไม่สามารถเปลี่ยนแปลงได้โดยธุรกรรมที่เกิดขึ้นพร้อมกันระหว่างการอ่านและการเขียนไปที่ N ตราบใดที่การอ่านและการเขียนเสร็จสิ้นในคำสั่ง SQL เดี่ยว


2

คำตอบที่บ้าอย่างแท้จริง แต่ถ้าคุณมีระบบการจำลองแบบบางประเภท (สำหรับระบบที่มีพันล้านแถวฉันหวังว่าคุณจะทำ) คุณสามารถใช้ตัวประมาณคร่าวๆได้ (เช่น MAX(pk) ) หารค่านั้นด้วยจำนวนทาส คุณมีให้เรียกใช้แบบสอบถามหลายขนาน

ส่วนใหญ่คุณจะแบ่งการค้นหาข้ามทาสโดยใช้คีย์ที่ดีที่สุด (หรือคีย์หลักที่ฉันเดา) ในลักษณะนี้ (เราจะใช้ 250000000 เป็น Rows / Slaves ของเรา):

-- First slave
SELECT COUNT(pk) FROM t WHERE pk < 250000000
-- Ith slave where 2 <= I <= N - 1
SELECT COUNT(pk) FROM t WHERE pk >= I*250000000 and pk < (I+1)*250000000
-- Last slave
SELECT COUNT(pk) FROM t WHERE pk > (N-1)*250000000

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

CREATE TABLE counter_table (minpk integer, maxpk integer, cnt integer, slaveid integer)

ดังนั้นแทนที่จะมีตัวเลือกที่ทำงานอยู่ในทาสของคุณคุณจะต้องทำการแทรกคล้ายกับสิ่งนี้:

INSERT INTO counter_table VALUES (I*25000000, (I+1)*250000000, (SELECT COUNT(pk) FROM ... ), @@SLAVE_ID)

คุณอาจพบปัญหาเกี่ยวกับทาสที่เขียนลงในตารางบนต้นแบบ คุณอาจต้องเศร้ามากขึ้น - ฉันหมายถึงความคิดสร้างสรรค์:

-- A table per slave!
INSERT INTO counter_table_slave_I VALUES (...)

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

ณ จุดนี้คุณจะต้องทำฟังก์ชั่นรวมเพื่อหาว่าแถวรวมคืออะไร แต่จะง่ายกว่าเนื่องจากคุณจะเรียกใช้งานได้มากที่สุดในแถว "จำนวนทาสที่คุณมีและเปลี่ยน"

หากคุณอยู่ในสถานการณ์ที่คุณมีตารางแยกกันในทาสคุณสามารถUNIONรับแถวทั้งหมดที่คุณต้องการ

SELECT SUM(cnt) FROM (
    SELECT * FROM counter_table_slave_1
      UNION
    SELECT * FROM counter_table_slave_2
      UNION
    ...
  )

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

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

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

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

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

ดังนั้นมีสองเพนนีปี 2013 ของฉัน


2

หากใช้ทริกเกอร์แทรกราคาแพงเกินไป แต่สามารถลบทริกเกอร์ได้และมีการเพิ่มขึ้นอัตโนมัติidหลังจากนับตารางทั้งหมดหนึ่งครั้งและจดจำการนับเป็นlast-countและlast-counted-id ,

แล้วในแต่ละวันก็ต้องนับid> last-counted-id, เพิ่มที่และเก็บใหม่last-countlast-counted-id

ทริกเกอร์การลบจะลดจำนวนครั้งสุดท้ายหาก id ของบันทึกที่ถูกลบ <= จำนวนครั้งสุดท้ายนับ


.. ขอโทษไม่มีเวลาที่จะแสดง SQL ที่จะใช้ (SQL ของฉันเป็นสนิม) หากใครต้องการแก้ไขคำตอบของฉันเพื่อเพิ่ม SQL นั่นจะดีมาก!
ToolmakerSteve

1

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

SELECT TOP(1) <primarykeyfield> FROM <table> ORDER BY <primarykeyfield> DESC;

ฉันทำงานกับตาราง MS SQL ที่มีหลายพันล้านแถวที่ต้องใช้เวลาตอบสนองย่อยสำหรับข้อมูลรวมถึงจำนวนระเบียน SELECT COUNT ที่คล้ายกัน (*) จะใช้เวลาในการประมวลผลโดยการเปรียบเทียบ


1
ไม่เป็นความจริงทั้งหมด - จะเกิดอะไรขึ้นถ้าINSERTธุรกรรมถูกย้อนกลับ ค่าคีย์หลักนั้นจะหายไปดังนั้นจำนวนเรคคอร์ดที่แท้จริงจะน้อยกว่าค่าสูงสุดหนึ่งรายการ
เซอร์ Crispalot

อาจเป็นช่องว่างในลำดับ มักจะเป็นผลมาจากการย้อนกลับ
Osa E

ที่จริงแล้วมีการแก้ไขคำตอบนี้ที่อาจเร็วกว่าอย่างมีนัยสำคัญcount(*)หากผู้ขายฐานข้อมูลไม่ได้รับการปรับให้เหมาะสมอย่างเพียงพอcount(*): ในแต่ละวันติดตามดัชนีอัตโนมัติครั้งล่าสุดและจำนวนที่สอดคล้องกันแล้วขอบันทึกนับจาก ยังสามารถจัดการกับdeletes หากเพิ่มทริกเกอร์ในการลบที่ลดผลรวมก่อนหน้านี้ถ้าลบบันทึก id <= ที่ดัชนีอัตโนมัติล่าสุด
ToolmakerSteve

1

สำหรับเซิร์ฟเวอร์ SQL ลองทำสิ่งนี้

SELECT T.name, 
       I.rows AS [ROWCOUNT] 
FROM   sys.tables AS T 
       INNER JOIN sys.sysindexes AS I 
               ON T.object_id = I.id AND I.indid < 2 
WHERE T.name = 'Your_Table_Name'
ORDER  BY I.rows DESC 


0

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


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

0

หากคุณใช้ Oracle วิธีการนี้ (สมมติว่าสถิติตารางได้รับการอัปเดต):

select <TABLE_NAME>, num_rows, last_analyzed from user_tables

last_analyzed จะแสดงเวลาที่รวบรวมสถิติครั้งล่าสุด



-1

ใน SQL Server 2016 ฉันสามารถตรวจสอบคุณสมบัติของตารางแล้วเลือกแท็บ 'ที่เก็บข้อมูล' ซึ่งจะทำให้ฉันมีจำนวนแถวพื้นที่ดิสก์ที่ใช้โดยตารางพื้นที่ดัชนีที่ใช้เป็นต้น


database vendor independent solutionเขาได้รับการมองหา นอกจากนี้ยังต้องใช้ GUI และไม่สามารถเป็นแบบอัตโนมัติได้ นอกจากนี้ยังไม่เร็วเท่า COUNT (*)
Frieder

-3

อาจจะสายไปบ้าง แต่สิ่งนี้อาจช่วยผู้อื่นสำหรับ MSSQL

; กับ RecordCount AS (SELECT ROW_NUMBER () ขึ้นไป (เรียงตาม COLUMN_NAME) เป็น [RowNumber] จาก Table_NAME) เลือก MAX (RowNumber) จาก RecordCount


สิ่งนี้มีความหมายมากกว่า COUNT () เว้นแต่ว่าเราโชคดีมากและเครื่องมือเพิ่มประสิทธิภาพจัดการเพื่อเพิ่มประสิทธิภาพให้เป็น COUNT () - ทำไมจึงขอให้ SORT บนคอลัมน์สุ่ม!?
dsz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.