Count (*) vs Count (1) - เซิร์ฟเวอร์ SQL


738

เพียงแค่สงสัยว่าถ้าใด ๆ ของคุณที่คนใช้Count(1)มากกว่าCount(*)และหากมีความแตกต่างที่เห็นได้ชัดในการปฏิบัติงานหรือถ้านี้เป็นเพียงนิสัยเดิมที่ได้รับการยกมาจากวันที่ผ่านมาหายไป?

SQL Server 2005ฐานข้อมูลเฉพาะคือ


7
ไม่ทราบเกี่ยวกับ SQL Server แต่ใน MySQL ไม่มีความแตกต่าง COUNT (คอลัมน์) ในทางกลับกันจะแตกต่างกัน
Greg

118
ไม่จริง. COUNT (SomeColumn) จะส่งคืนจำนวนแถวที่มีค่าที่ไม่เป็นศูนย์สำหรับ SomeColumn เท่านั้น COUNT (*) และ COUNT ('Foo') จะส่งคืนจำนวนแถวทั้งหมดในตาราง
Steve Broberg

1
สำหรับรายละเอียดเพิ่มเติมให้ตรวจสอบการนับ
Ali Adravi

4
Wow Steve และที่นี่ฉันใช้เวลา 5 ปีใน TSQL โดยไม่ทราบจำนวน (*) vs Count (ColumnName) ขอบคุณ
Harindaka

3
หมายเหตุด้วยคำตอบของCOUNT(*)vs COUNT(1)vs COUNT(pk)- ไหนดีกว่ากัน? . นอกจากนี้ยังมีCOUNT(*)vs COUNT(column-name)- ซึ่งถูกต้องมากขึ้น? . อาจมีการซ้ำซ้อนอื่น ๆ
Jonathan Leffler

คำตอบ:


598

ไม่มีความแตกต่าง

เหตุผล:

หนังสือออนไลน์พูดว่า " COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )"

"1" คือการแสดงออกที่ไม่ null: COUNT(*)ดังนั้นจึงเป็นเรื่องเดียวกับ เครื่องมือเพิ่มประสิทธิภาพรู้ว่ามันคืออะไร: เล็กน้อย

เช่นเดียวกับEXISTS (SELECT * ...หรือEXISTS (SELECT 1 ...

ตัวอย่าง:

SELECT COUNT(1) FROM dbo.tab800krows
SELECT COUNT(1),FKID FROM dbo.tab800krows GROUP BY FKID

SELECT COUNT(*) FROM dbo.tab800krows
SELECT COUNT(*),FKID FROM dbo.tab800krows GROUP BY FKID

IO เดียวกันแผนเดียวกันผลงาน

แก้ไข ส.ค. 2554

คำถามที่คล้ายกันใน DBA.SE

แก้ไขธันวาคม 2011

COUNT(*)ถูกกล่าวถึงโดยเฉพาะในANSI-92 (มองหา " Scalar expressions 125")

กรณี:

a) หากระบุ COUNT (*) ผลที่ได้คือ cardinality ของ T

นั่นคือมาตรฐาน ANSI ยอมรับว่ามีเลือดออกชัดเจนว่าคุณหมายถึงอะไร COUNT(1)ได้รับการปรับให้เหมาะสมโดยผู้จำหน่าย RDBMS เนื่องจากความเชื่อโชคลางนี้ มิฉะนั้นจะได้รับการประเมินตาม ANSI

b) มิฉะนั้นให้ TX เป็นตารางคอลัมน์เดี่ยวที่เป็นผลลัพธ์ของการใช้ <value expression> กับแต่ละแถวของ T และกำจัดค่า Null หากมีการลบค่า Null หนึ่งค่าขึ้นไปเงื่อนไขการเติมจะสมบูรณ์ขึ้น: warning-


73

ใน SQL Server งบเหล่านี้ให้ผลแผนเดียวกัน

ตรงกันข้ามกับความคิดเห็นยอดนิยมใน Oracle พวกเขาก็ทำเช่นกัน

SYS_GUID() ใน Oracle เป็นฟังก์ชั่นการคำนวณที่ค่อนข้างเข้มข้น

ในฐานข้อมูลทดสอบของฉันt_evenคือตารางที่มี1,000,000แถว

แบบสอบถามนี้:

SELECT  COUNT(SYS_GUID())
FROM    t_even

วิ่ง48วินาทีเนื่องจากความต้องการฟังก์ชั่นในการประเมินแต่ละกลับไปให้แน่ใจว่ามันไม่ได้เป็นSYS_GUID()NULL

อย่างไรก็ตามคำค้นหานี้:

SELECT  COUNT(*)
FROM    (
        SELECT  SYS_GUID()
        FROM    t_even
        )

วิ่งไป แต่2วินาทีเพราะมันไม่ได้พยายามประเมินSYS_GUID()(แม้จะ*เป็นข้อโต้แย้งCOUNT(*))


ควรประเมินSYS_GUID()อย่างน้อย (ฉันหมายถึงอย่างแน่นอน) หนึ่งครั้งสำหรับเคียวรีย่อยเพื่อส่งคืนผลลัพธ์ใช่ไหม
asgs

@asgs: ทำไมคุณคิดอย่างนั้น วิธีการที่ไม่COUNT(*)ขึ้นอยู่กับค่าของSYS_GUID?
Quassnoi

ตอนนี้คุณถามฉันไม่แน่ใจ ฉันคิดว่าCOUNT(*)จะเรียกใช้จำเป็นต้องมีตารางดังนั้นแบบสอบถามย่อยควรทำหน้าที่เหมือนกัน มิฉะนั้นฉันไม่เห็นวิธีที่COUNT(*)จะคืนค่าที่มีความหมาย
asgs

1
@asgs: สมมติว่าคุณรู้ว่าmapวิธีการทำอะไรคุณจะเห็นว่าการแสดงออกทั้งสองนี้: t_even.map(() => sys_guid()).lengthและt_even.lengthจะคืนค่าเดียวกันเสมอ? เครื่องมือเพิ่มประสิทธิภาพของ Oracle นั้นฉลาดพอที่จะมองเห็นและปรับแต่งmapส่วนต่างๆให้เหมาะสม
Quassnoi

1
@ แน่นอน เพียงแค่การแก้ไขเล็กน้อย: lengthไม่ได้ขึ้นอยู่กับสิ่งที่คอลเลกชันประกอบด้วยเพียงแค่จำนวนขององค์ประกอบ หากตัวเลขนี้ถูกเก็บไว้ในข้อมูลเมตาของคอลเลกชัน (นี่ไม่ใช่กรณีของ Oracle หรือ RDBMS ที่ทันสมัยที่สุด แต่เป็นกรณีของเครื่องมือเก็บข้อมูล MySQL เก่า MyISAM) ก็COUNT(*)จะต้องใช้ค่าจากข้อมูลเมตา
Quassnoi

65

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


ฉันจะไม่คิดว่ามันเป็นข้อผิดพลาดหากการนับ (1) ช้ากว่าการนับ (*) หากคุณขอให้ dbms สร้าง 1s และนับจำนวนที่ไม่ใช่ null ดังนั้นใช่มันจะลดลงเพื่อนับจำนวนเรคคอร์ด แต่คุณไม่สามารถคาดหวังได้ว่า dbms จะตรวจสอบทุกเรื่องไร้สาระที่คุณเขียนและหลีกเลี่ยงมันสำหรับคุณ
Thorsten Kettner

1
เครื่องมือเพิ่มประสิทธิภาพนั้นมีจุดประสงค์เพื่อปรับให้เหมาะสมและสำหรับการนับมีเพียง 2 กรณีที่ต้องพิจารณา: นิพจน์ที่อาจเป็นโมฆะนิพจน์ที่ไม่เป็นโมฆะ: นับ (1) ตกหลุมหลังดังนั้นจึงไม่มีความจำเป็นสำหรับ DBMS "สร้าง" 1 วินาทีเพื่อตอบคำถาม (BTW ฉันจะไม่ใช้อะไรนอกจากนับ (*) เพียงเพื่อเหตุผลด้านความสวยงาม)
Tony Andrews

46

ฉันทำงานกับทีม SQL Server และฉันหวังว่าจะสามารถชี้แจงบางประเด็นในหัวข้อนี้ (ฉันไม่เคยเห็นมาก่อนดังนั้นฉันจึงเสียใจที่ทีมวิศวกรรมยังไม่ได้ทำไปก่อนหน้านี้)

ครั้งแรกไม่มีความแตกต่างระหว่างความหมายกับselect count(1) from table select count(*) from tableพวกเขากลับผลลัพธ์เดียวกันในทุกกรณี (และเป็นข้อผิดพลาดถ้าไม่) ตามที่ระบุไว้ในคำตอบอื่น ๆที่แตกต่างกันความหมายและไม่เคยกลับผลเช่นเดียวกับselect count(column) from tablecount(*)

ประการที่สองเกี่ยวกับประสิทธิภาพมีสองด้านที่สำคัญใน SQL Server (และ SQL Azure): งานรวบรวมเวลาและงานเวลาดำเนินการ การรวบรวมเวลาทำงานเป็นงานพิเศษจำนวนเล็กน้อยในการใช้งานปัจจุบัน มีการขยายตัวของ * ไปยังคอลัมน์ทั้งหมดในบางกรณีตามด้วยการลดกลับไปที่ 1 คอลัมน์ที่มีการส่งออกเนื่องจากการดำเนินงานภายในบางอย่างในการเชื่อมโยงและการเพิ่มประสิทธิภาพ ฉันสงสัยว่ามันจะปรากฏขึ้นในการทดสอบใด ๆ ที่วัดได้และมันอาจจะหายไปในเสียงรบกวนของสิ่งอื่น ๆ ทั้งหมดที่เกิดขึ้นภายใต้ฝาครอบ (เช่นสถิติอัตโนมัติช่วงเวลา xevent โอเวอร์เฮดของที่เก็บแบบสอบถามทริกเกอร์ ฯลฯ ) อาจเป็นคำสั่ง CPU เพิ่มเติมสองสามพันคำสั่ง ดังนั้น, นับ (1) ทำงานน้อยลงเล็กน้อยในระหว่างการรวบรวม (ซึ่งมักจะเกิดขึ้นเพียงครั้งเดียวและแผนนั้นถูกแคชไว้ในการประมวลผลครั้งต่อ ๆ มาหลายรายการ) สำหรับเวลาดำเนินการสมมติว่าแผนเหมือนกันไม่ควรมีความแตกต่างที่วัดได้ (หนึ่งในตัวอย่างก่อนหน้านี้แสดงความแตกต่าง - เป็นไปได้มากที่สุดเนื่องจากปัจจัยอื่น ๆ บนเครื่องหากแผนเหมือนกัน)

ว่าแผนอาจแตกต่างกันอย่างไร สิ่งเหล่านี้ไม่น่าจะเกิดขึ้นได้มากนัก แต่อาจเป็นไปได้ในสถาปัตยกรรมของเครื่องมือเพิ่มประสิทธิภาพปัจจุบัน เครื่องมือเพิ่มประสิทธิภาพของ SQL Server ทำงานเป็นโปรแกรมค้นหา (คิดว่า: โปรแกรมคอมพิวเตอร์ที่เล่นหมากรุกค้นหาผ่านทางเลือกต่าง ๆ สำหรับส่วนต่าง ๆ ของการสืบค้นและการคิดต้นทุนทางเลือกเพื่อค้นหาแผนการที่ถูกที่สุดในเวลาที่เหมาะสม) การค้นหานี้มีข้อ จำกัด เล็กน้อยเกี่ยวกับวิธีการทำงานเพื่อให้การรวบรวมแบบสอบถามเสร็จในเวลาที่เหมาะสม สำหรับข้อความค้นหาที่เกินความคาดหมายมีขั้นตอนของการค้นหาและจะจัดการกับชุดข้อความค้นหาตามวิธีที่เครื่องมือเพิ่มประสิทธิภาพราคาคิดว่าแบบสอบถามนั้นมีแนวโน้มที่จะดำเนินการ มี 3 ขั้นตอนการค้นหาหลักและแต่ละขั้นตอนสามารถใช้การวิเคราะห์พฤติกรรมแบบก้าวร้าว (แพง) ที่พยายามค้นหาแผนการราคาถูกกว่าโซลูชันก่อนหน้านี้ ในที่สุดมีกระบวนการตัดสินใจในตอนท้ายของแต่ละขั้นตอนที่พยายามกำหนดว่าควรส่งคืนแผนที่พบจนถึงตอนนี้หรือควรค้นหาต่อไป กระบวนการนี้ใช้เวลาทั้งหมดที่ดำเนินการจนถึงกับต้นทุนโดยประมาณของแผนที่ดีที่สุดที่พบจนถึงขณะนี้ ดังนั้นในเครื่องที่แตกต่างกันด้วยความเร็วที่แตกต่างกันของซีพียูมันเป็นไปได้ (แม้ว่าจะหายาก) ในการรับแผนที่แตกต่างกันเนื่องจากหมดเวลาในช่วงก่อนหน้านี้กับแผนเทียบกับดำเนินการต่อในขั้นตอนการค้นหาถัดไป นอกจากนี้ยังมีสถานการณ์ที่คล้ายกันสองสามอย่างที่เกี่ยวข้องกับการหมดเวลาของช่วงสุดท้ายและอาจมีหน่วยความจำเหลือน้อยในแบบสอบถามที่มีราคาแพงมากและใช้หน่วยความจำทั้งหมดในเครื่อง กลับสู่เซิร์ฟเวอร์ 32 บิต) ในที่สุดหากคุณได้รับแผนแตกต่างกันประสิทธิภาพที่รันไทม์จะแตกต่างกัน ฉันไม่ '

Net-net: โปรดใช้สิ่งใดสิ่งหนึ่งในสองสิ่งที่คุณต้องการว่าไม่มีเรื่องนี้ในรูปแบบที่ใช้งานได้จริง (มีปัจจัยที่ใหญ่กว่ามากที่ส่งผลกระทบต่อประสิทธิภาพการทำงานของ SQL ในหัวข้อนี้โดยสุจริต)

ฉันหวังว่านี่จะช่วยได้. ฉันเขียนบทหนังสือเกี่ยวกับวิธีเพิ่มประสิทธิภาพการทำงาน แต่ฉันไม่รู้ว่ามันเหมาะสมที่จะโพสต์ไว้ที่นี่หรือไม่ ดังนั้นแทนที่จะโพสต์ว่าฉันจะโพสต์ลิงก์ไปยังการพูดคุยที่ฉันให้ที่ SQLBits ในสหราชอาณาจักรเกี่ยวกับวิธีที่เครื่องมือเพิ่มประสิทธิภาพการทำงานในระดับสูงเพื่อให้คุณสามารถเห็นขั้นตอนหลักที่แตกต่างกันของการค้นหาในรายละเอียดเพิ่มเติมเล็กน้อย เพื่อเรียนรู้เกี่ยวกับสิ่งนั้น นี่คือลิงค์วิดีโอ: https://sqlbits.com/Sessions/Event6/inside_the_sql_server_query_optimizer


2
ความเชื่อของฉันคือสิ่งนั้น1ก็ผ่านไปเช่นเดียวกัน ฉันยึดสิ่งนี้กับการทดสอบ perf ที่นี่stackoverflow.com/questions/1597442/ … ดูตัวอย่างในคำตอบของแบบสอบถามโดยใช้การ1ล้มเหลวโดยไม่คาดคิดเมื่อสิทธิ์ระดับคอลัมน์กำลังเล่นอยู่
Martin Smith

21

ในมาตรฐาน SQL-92 COUNT(*)โดยเฉพาะหมายถึง "ความสำคัญของการแสดงออกของตาราง" (อาจเป็นตารางฐาน `ดูตารางที่ได้รับ CTE ฯลฯ )

ฉันเดาว่าความคิดนั้นCOUNT(*)ง่ายในการแยก โดยใช้การแสดงออกอื่น ๆ ต้องแยกวิเคราะห์เพื่อให้แน่ใจว่าไม่อ้างอิงคอลัมน์ใด ๆ ( COUNT('a')ที่aเป็นตัวอักษรและCOUNT(a)ที่aเป็นคอลัมน์ที่สามารถให้ผลลัพธ์ที่แตกต่างกัน)

ในหลอดเลือดดำเดียวกันCOUNT(*)สามารถเลือกมนุษย์ coder ที่คุ้นเคยกับมาตรฐาน SQL ซึ่งเป็นทักษะที่มีประโยชน์เมื่อทำงานกับข้อเสนอ SQL ของผู้ค้ามากกว่าหนึ่งราย

นอกจากนี้ในกรณีพิเศษSELECT COUNT(*) FROM MyPersistedTable;ความคิดคือ DBMS มีแนวโน้มที่จะเก็บสถิติสำหรับความสำคัญของตาราง

ดังนั้นเพราะCOUNT(1)และมีความหมายเทียบเท่าผมใช้COUNT(*)COUNT(*)


1
ข้อความ SQL-92 เชื่อมโยงจากคำตอบของฉันใน DBA.SE: dba.stackexchange.com/questions/2511/…
gbn


12

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

วิธีเดียวที่จะบอกได้ก็คือวัดทุกกรณี

COUNT(*)ที่กล่าวว่าฉันได้ใช้เสมอ


ตามคำตอบที่ยอมรับแล้วสิ่งนี้ไม่เป็นความจริงสำหรับ MS SQL - ไม่มีความแตกต่างระหว่างทั้งสอง
David Manheim

10

เมื่อคำถามนี้เกิดขึ้นซ้ำแล้วซ้ำอีกนี่คือคำตอบอีกหนึ่งข้อ ฉันหวังว่าจะเพิ่มบางสิ่งสำหรับผู้เริ่มต้นที่สงสัยเกี่ยวกับ "วิธีปฏิบัติที่ดีที่สุด" ที่นี่

SELECT COUNT(*) FROM something นับระเบียนซึ่งเป็นงานง่าย

SELECT COUNT(1) FROM something ดึง 1 ต่อเร็กคอร์ดและนับจำนวน 1s ที่ไม่ใช่ค่า null ซึ่งเป็นการนับเร็กคอร์ดที่ซับซ้อนเท่านั้น

ต้องกล่าวสิ่งนี้ดี dbms สังเกตว่าคำสั่งที่สองจะส่งผลในการนับเช่นเดียวกับคำสั่งแรกและ interprete อีกครั้งตามที่จะไม่ทำงานที่ไม่จำเป็น ดังนั้นโดยปกติแล้วข้อความทั้งสองจะส่งผลให้เกิดแผนการดำเนินการเดียวกันและใช้เวลาเท่ากัน

อย่างไรก็ตามจากจุดที่อ่านได้คุณควรใช้คำสั่งแรก คุณต้องการนับระเบียนดังนั้นนับระเบียนไม่ใช่นิพจน์ ใช้ COUNT (นิพจน์) เฉพาะเมื่อคุณต้องการนับสิ่งที่ไม่เป็นโมฆะของบางสิ่งบางอย่าง


8

ฉันรันการทดสอบอย่างรวดเร็วบน SQL Server 2012 บนกล่อง Hyper-v 8 GB RAM คุณสามารถเห็นผลลัพธ์ได้ด้วยตัวคุณเอง ฉันไม่ได้ใช้แอพพลิเคชั่นที่มีหน้าต่างอื่นนอกเหนือจาก SQL Server Management Studio ขณะทำการทดสอบเหล่านี้

สคีมาของตารางของฉัน:

CREATE TABLE [dbo].[employee](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_employee] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

จำนวนระเบียนทั้งหมดในEmployeeตาราง: 178090131 (ประมาณ 178 ล้านแถว)

คำค้นหาแรก:

Set Statistics Time On
Go    
Select Count(*) From Employee
Go    
Set Statistics Time Off
Go

ผลการค้นหาครั้งแรก:

 SQL Server parse and compile time: 
 CPU time = 0 ms, elapsed time = 35 ms.

 (1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 10766 ms,  elapsed time = 70265 ms.
 SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

คำค้นหาที่สอง:

    Set Statistics Time On
    Go    
    Select Count(1) From Employee
    Go    
    Set Statistics Time Off
    Go

ผลการค้นหาครั้งที่สอง:

 SQL Server parse and compile time: 
   CPU time = 14 ms, elapsed time = 14 ms.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 11031 ms,  elapsed time = 70182 ms.
 SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

คุณสามารถสังเกตเห็นว่ามีความแตกต่างของ 83 (= 70265 - 70182) มิลลิวินาทีซึ่งสามารถนำมาประกอบกับสภาพของระบบที่แน่นอนได้อย่างแม่นยำเมื่อมีการเรียกใช้แบบสอบถาม นอกจากนี้ฉันได้ทำการวิ่งครั้งเดียวดังนั้นความแตกต่างนี้จะแม่นยำมากขึ้นถ้าฉันวิ่งหลายครั้งและทำการเฉลี่ยโดยเฉลี่ย หากชุดข้อมูลขนาดใหญ่มีความแตกต่างน้อยกว่า 100 มิลลิวินาทีเราสามารถสรุปได้อย่างง่ายดายว่าเคียวรีสองรายการนั้นไม่มีความแตกต่างด้านประสิทธิภาพที่แสดงโดย SQL Server Engine

หมายเหตุ : RAM ใช้งานได้ใกล้ 100% ทั้งการรัน ฉันเริ่มบริการ SQL Server ใหม่ก่อนเริ่มการทำงานทั้งสองครั้ง


7
SET STATISTICS TIME ON

select count(1) from MyTable (nolock) -- table containing 1 million records. 

เวลาดำเนินการของ SQL Server:
เวลา CPU = 31 ms, เวลาที่ผ่านไป = 36 ms

select count(*) from MyTable (nolock) -- table containing 1 million records. 

เวลาดำเนินการของ SQL Server:
เวลา CPU = 46 ms, เวลาที่ผ่านไป = 37 ms

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


14
ฉันทำซ้ำไม่ได้ count(*)และcount(1)ส่งคืนผลลัพธ์ภายในไม่กี่มิลลิวินาทีของกันและกันแม้เมื่อนับจำนวนตารางที่มี 4.5 ล้านแถวใน SQL 2008 ของฉัน
Jeff Atwood

2
บางครั้งในบางระบบคำสั่งที่รันก่อนจะรันเร็วกว่า ... คุณเคยสุ่มลำดับที่พวกมันรันอยู่หรือไม่?
JosephDoggie

@JosephDoggie หนึ่งควรเริ่มบริการ SQL Server ก่อนที่จะเรียกใช้ทุกแบบสอบถามในขณะที่การวัด / สถิติดังกล่าว เมื่อคุณเพิ่งเริ่มให้บริการ SQL Server การรันทุกครั้งจะมีความเป็นอิสระอย่างสมบูรณ์และไม่ต้องคำนึงถึงลำดับของการสืบค้น ในทางกลับกันถ้าคุณไม่ได้เริ่มบริการ SQL Server และเอ็นจินใหม่ ๆ จะทำการแคชแผนปฏิบัติการบางอย่างดังนั้นแบบสอบถามที่ถูกเรียกใช้ในภายหลังควรรันได้เร็วกว่าไม่ใช่โปรแกรมแรก
RBT

เวลาดำเนินการต้องดูแผนแบบสอบถามที่แน่นอนเมื่อทำการเปรียบเทียบ หากพวกเขาแตกต่างกัน (เช่นรวมแฮชรวมกับเรียงลำดับ + สตรีมรวม) ผลลัพธ์จะไม่สามารถเปรียบเทียบกันได้ ดังนั้นฉันขอเตือนให้คุณหาข้อสรุปที่นี่โดยไม่มีข้อมูลเพิ่มเติม
Conor Cunningham MSFT

3

มีบทความที่แสดงให้เห็นว่าCOUNT(1)ในOracleเป็นเพียงนามแฝงที่COUNT(*)มีหลักฐานเกี่ยวกับเรื่องนี้

ฉันจะอ้างอิงบางส่วน:

มีส่วนหนึ่งของซอฟต์แวร์ฐานข้อมูลที่เรียกว่า "เครื่องมือเพิ่มประสิทธิภาพ" ซึ่งกำหนดไว้ในเอกสารประกอบอย่างเป็นทางการว่า "ซอฟต์แวร์ฐานข้อมูลในตัวซึ่งกำหนดวิธีที่มีประสิทธิภาพที่สุดในการดำเนินการคำสั่ง SQL"

หนึ่งในส่วนประกอบของออพติไมเซอร์เรียกว่า“ หม้อแปลง” ซึ่งมีหน้าที่ตรวจสอบว่ามันมีประโยชน์ที่จะเขียนคำสั่ง SQL ต้นฉบับลงในคำสั่ง SQL ที่เทียบเท่าความหมายซึ่งอาจมีประสิทธิภาพมากกว่า

คุณต้องการดูว่าเครื่องมือเพิ่มประสิทธิภาพทำอะไรเมื่อคุณเขียนข้อความค้นหาโดยใช้ COUNT (1)

กับผู้ใช้ที่มีALTER SESSIONสิทธิ์คุณสามารถใส่tracefile_identifierให้เปิดใช้งานการติดตามการเพิ่มประสิทธิภาพและรันเลือกเช่น:COUNT(1)SELECT /* test-1 */ COUNT(1) FROM employees;

หลังจากนั้นคุณจำเป็นต้อง จำกัด SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Diag Trace';วงไฟล์การติดตามสิ่งที่สามารถทำได้ด้วย ต่อมาในไฟล์คุณจะพบกับ:

SELECT COUNT(*) COUNT(1)” FROM COURSE”.”EMPLOYEES EMPLOYEES

COUNT(*)ในขณะที่คุณสามารถดูจะเป็นเพียงนามแฝงสำหรับ

ความคิดเห็นที่สำคัญอีกประการหนึ่งคือความCOUNT(*)รวดเร็วในสองทศวรรษที่ผ่านมาของ Oracle ก่อน Oracle 7.3:

Count (1) ได้รับการเขียนใหม่ใน count (*) ตั้งแต่ 7.3 เพราะ Oracle ชอบปรับแต่งข้อความที่เป็นตำนานโดยอัตโนมัติ ใน Oracle7 ก่อนหน้านี้ Oracle ต้องประเมิน (1) สำหรับแต่ละแถวในฐานะฟังก์ชันก่อนที่จะมี DETERMINISTIC และ NON-DETERMINISTIC

เมื่อสองทศวรรษที่แล้วการนับ (*) เร็วขึ้น

สำหรับฐานข้อมูลอื่นเช่น SQL Server ควรทำการวิจัยแยกต่างหากสำหรับแต่ละฐานข้อมูล

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


1

ใน RDBMS ทั้งหมดวิธีการนับสองวิธีนั้นเท่ากันในแง่ของผลลัพธ์ที่ได้ เกี่ยวกับประสิทธิภาพผมไม่ได้สังเกตเห็นความแตกต่างการใด ๆ ใน SQL Server แต่มันอาจจะมีมูลค่าการชี้ให้เห็นว่า RDBMS บางเช่น PostgreSQL 11 มีการใช้งานที่เหมาะสมน้อยกว่าCOUNT(1)ที่พวกเขาตรวจสอบ nullability การแสดงออกอาร์กิวเมนต์ที่สามารถมองเห็นในโพสต์นี้

ฉันพบความแตกต่างด้านประสิทธิภาพ 10% สำหรับแถว 1M เมื่อทำงาน:

-- Faster
SELECT COUNT(*) FROM t;

-- 10% slower
SELECT COUNT(1) FROM t;

0

COUNT (1) ไม่แตกต่างอย่างมีนัยสำคัญจาก COUNT (*) หากเลย สำหรับคำถามของ COUNTing NULLable COLUMNs สิ่งนี้สามารถอธิบายความแตกต่างระหว่าง COUNT (*) และ COUNT (<some col>) ได้โดยตรง

USE tempdb;
GO

IF OBJECT_ID( N'dbo.Blitzen', N'U') IS NOT NULL DROP TABLE dbo.Blitzen;
GO

CREATE TABLE dbo.Blitzen (ID INT NULL, Somelala CHAR(1) NULL);

INSERT dbo.Blitzen SELECT 1, 'A';
INSERT dbo.Blitzen SELECT NULL, NULL;
INSERT dbo.Blitzen SELECT NULL, 'A';
INSERT dbo.Blitzen SELECT 1, NULL;

SELECT COUNT(*), COUNT(1), COUNT(ID), COUNT(Somelala) FROM dbo.Blitzen;
GO

DROP TABLE dbo.Blitzen;
GO
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.