MySQL ชดเชยแถวที่ไม่มีที่สิ้นสุด


114

ฉันต้องการสร้างแบบสอบถามที่แสดงผลลัพธ์ทั้งหมดในตาราง แต่ถูกชดเชยด้วย 5 จากจุดเริ่มต้นของตาราง เท่าที่ฉันสามารถบอกได้ MySQL LIMITต้องมีขีด จำกัด เช่นเดียวกับการชดเชย มีวิธีใดบ้างที่จะทำเช่นนี้?


1
นี่เป็นคำถามที่ถูกต้องโดยสิ้นเชิง แต่ฉันสงสัยว่าสิ่งที่จะดีกว่าคือการคว้าทุกสิ่งและไม่สนใจบันทึกสองสามรายการแรกโดยใช้โปรแกรม เมื่อพิจารณาถึงความน่ากลัวของสิ่งที่ดูเหมือนจะเป็นคำตอบที่ดีที่สุด (ขีด จำกัด 5, 18446744073709551615) ฉันชอบทำงานกับข้อ จำกัด ของ MySQL LIMIT อย่างมาก
cesoid

3
@cesoid ถ้าคุณต้องการlimit 5000, 18446744073709551615อะไร คุณจะไม่ดึงข้อมูลเพิ่มอีก 5,000 แถวเพียงเพื่อให้โค้ดของคุณดูสวย
elipoultorak

@ user3576887 ฉันคิดว่าคุณพูดถูกฉันแค่พิจารณาคำถามข้างต้นโดยมีสมมติฐานว่า 5 เป็นข้อกำหนดเดียวแทนที่จะเป็นจำนวนเงินที่แตกต่างกันซึ่งอาจมากกว่ามาก (และแทนที่จะแก้ปัญหาของคนอื่น)
cesoid

ฉันขอแนะนำว่านี่เป็นงานที่หาได้ยากซึ่งสามารถยอมรับความน่าเกลียดของโซลูชันได้
Rick James

คำตอบ:


152

จากคู่มือ MySQL เรื่อง LIMIT :

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

SELECT * FROM tbl LIMIT 95, 18446744073709551615;

105
อันยิ่งใหญ่! ฉันมาที่นี่โดยหวังว่า MySQL จะสร้าง Limit clause ให้เป็นทางเลือกเหมือนเดิม แต่ก็มีการชดเชยให้ด้วย ... แต่ไม่! ฉันเคยเห็น 18446744073709551615 กระจายไปทั่วโค้ดและฉันโทษโปรแกรมเมอร์ขี้เกียจ แต่มันเป็นคุณสมบัติการออกแบบ!
Petruza

8
คำตอบที่แย่มาก แต่นั่นเป็นทางการจาก MySQL Doc มีอะไรบอกได้นะ @ _ @
GusDeCooL

21
18446744073709551615 คือ 2 ^ 64-1 สำหรับผู้ที่สงสัย คุณอาจต้องระวังเพราะคุณจะเก็บค่านี้เป็นจำนวนเต็ม 32 บิตไม่ได้ คุณต้องแน่ใจว่าคุณจัดเก็บสิ่งนี้เป็นสตริงเพื่อให้แน่ใจว่าเข้ากันได้
AlicanC

13
น่ากลัว! ต้องสวยหรูกว่านั้น ... Limit -1หรือLimit Nullดูสมเหตุสมผลดี! หรือ atleast Limit ควรยอมรับคำค้นหาย่อยเช่นselect * from table limit (select count(*) from table)
vulcan raven

19
ใช้ php 'PHP_INT_MAX' เพื่อหลีกเลี่ยงเอฟเฟกต์ล้น
Karl Adler

24

ดังที่คุณกล่าวไว้ว่าต้องมี LIMIT ดังนั้นคุณต้องใช้ขีด จำกัด ที่ใหญ่ที่สุดเท่าที่จะเป็นไปได้ซึ่งก็คือ 18446744073709551615 (สูงสุดของ BIGINT ที่ไม่ได้ลงชื่อ)

SELECT * FROM somewhere LIMIT 18446744073709551610 OFFSET 5

33
ว้าวนี่เป็นโซลูชันอย่างเป็นทางการจากทีม MySQL หรือไม่?
Antony

12

ตามที่ระบุไว้ในคำตอบอื่น ๆ MySQL แนะนำให้ใช้ 18446744073709551615 เป็นจำนวนเรกคอร์ดในขีด จำกัด แต่ให้พิจารณาสิ่งนี้: คุณจะทำอย่างไรถ้าคุณได้รับ 18,446,744,073,709,551,615 ระเบียนกลับคืนมา ในความเป็นจริงคุณจะทำอย่างไรถ้าคุณมีประวัติ 1,000,000,000 รายการ?

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

หากคุณต้องได้รับบันทึกทั้งหมด 18 quintillion จากฐานข้อมูลของคุณบางทีสิ่งที่คุณต้องการจริงๆคือการคว้ามันทีละ 100 ล้านและวนซ้ำ 184 พันล้านครั้ง


คุณมีสิทธิ แต่การรักษาการตัดสินใจครั้งนี้ให้กับนักพัฒนาไม่ได้เป็นทางเลือกที่ดี
เอเอ็มดี

@amd ช่วยอธิบายอีกหน่อยได้ไหม ฉันไม่รู้ว่าคุณพยายามจะพูดอะไร
cesoid

1
@cesoid ฉันคิดว่าเขาบอกว่า devs ไม่ควรเป็นคนที่เลือกตรรกะทางธุรกิจโดยพลการซึ่งฉันเห็นด้วย แต่เพียงประเด็นเดียว สมมติว่าคุณกำลังส่งคืนรายการคำสั่งซื้อให้กับลูกค้า เป็นเรื่องสมเหตุสมผลอย่างยิ่งที่จะไม่ส่งคืนมากกว่าหนึ่งล้านครั้ง แต่การ จำกัด ไว้ที่ 100 อาจทำให้เกิดความสับสน
Autumn Leonard

@amd ฉันไม่ได้บอกว่านักพัฒนาควรเปลี่ยนพฤติกรรมของแอพเพื่อหลีกเลี่ยงการใช้ 18446744073709551615 ฉันบอกว่าพวกเขาควรพิจารณาว่าการใช้หมายเลขนั้นเหมาะสมหรือไม่โดยเป็นส่วนหนึ่งของการใช้งานสิ่งที่ไคลเอนต์หรือตัวออกแบบอินเทอร์เฟซ ได้ร้องขอและเป็นไปได้ยากมากที่จะใช้งานได้อย่างถูกต้องสำหรับสิ่งใด ๆ การตัดสินใจใช้ MySQL อาจเกิดขึ้นแล้วโดยนักพัฒนาโดยไม่ได้ถามว่าจะมีมากกว่า 18 quintillion หรือไม่
cesoid

5

อีกวิธีหนึ่งคือการเลือกคอลัมน์ที่เพิ่มอัตโนมัติแล้วกรองโดยใช้ HAVING

SET @a := 0; 
select @a:=@a + 1 AS counter, table.* FROM table 
HAVING counter > 4

แต่ฉันอาจจะยึดติดกับวิธีการ จำกัด สูง


ขอบคุณและฉันสงสัยว่าฉันจะใส่ข้อความค้นหาดังกล่าวในคำสั่ง PHP ได้อย่างไร! ฉันหมายถึงแบบนั้น$sql = 'SET @a :=0 SELECT .....';
Reham Fahmy

2

ดังที่คนอื่น ๆ กล่าวถึงจากคู่มือ MySQL เพื่อให้บรรลุเป้าหมายนั้นคุณสามารถใช้ค่าสูงสุดของ int ขนาดใหญ่ที่ไม่ได้ลงนามนั่นคือตัวเลขที่น่ากลัวนี้ (18446744073709551615) แต่เพื่อให้ยุ่งน้อยลงคุณสามารถใช้เครื่องหมายตัวหนอน "~" แบบบิตได้

  LIMIT 95, ~0

มันทำงานเป็นการปฏิเสธระดับบิต ผลลัพธ์ของ "~ 0" คือ 18446744073709551615


1
ไม่ทำงานใน MariaDB 10.3 :( ฉันลองทั้งสองอย่างLIMIT 5, ~0และLIMIT ~0 OFFSET 5นี่เป็นคุณสมบัติ MySQL 8.0 หรือไม่
jurchiks

1
นี่ไม่ใช่สิ่งใน MySQL 5.7 - ไวยากรณ์ไม่ถูกต้อง
Jonny Nott

0

วันนี้ฉันอ่านเกี่ยวกับวิธีที่ดีที่สุดในการรับข้อมูลจำนวนมาก (มากกว่าหนึ่งล้านแถว) จากตาราง mysql วิธีหนึ่งคือตามที่แนะนำโดยใช้LIMIT x,yตำแหน่งที่xเป็นออฟเซ็ตและyแถวสุดท้ายที่คุณต้องการส่งคืน อย่างไรก็ตามตามที่ฉันพบมันไม่ใช่วิธีที่มีประสิทธิภาพที่สุดในการทำเช่นนั้น หากคุณมีคอลัมน์การสร้างอัตโนมัติคุณสามารถใช้SELECTคำสั่งที่มีWHEREประโยคบอกว่าคุณต้องการเริ่มจากบันทึกใดได้อย่างง่ายดาย

ตัวอย่างเช่น, SELECT * FROM table_name WHERE id > x;

ดูเหมือนว่า mysql จะได้รับผลลัพธ์ทั้งหมดเมื่อคุณใช้LIMITจากนั้นจะแสดงเฉพาะระเบียนที่เหมาะสมกับค่าชดเชยเท่านั้น: ไม่ใช่สิ่งที่ดีที่สุดสำหรับประสิทธิภาพ

แหล่งที่มา: คำตอบสำหรับคำถามนี้ฟอรั่ม MySQL เพิ่งทราบว่าคำถามอายุประมาณ 6 ขวบ


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

0

คุณสามารถใช้คำสั่ง MySQL กับ LIMIT:

START TRANSACTION;
SET @my_offset = 5;
SET @rows = (SELECT COUNT(*) FROM my_table);
PREPARE statement FROM 'SELECT * FROM my_table LIMIT ? OFFSET ?';
EXECUTE statement USING @rows, @my_offset;
COMMIT;

ทดสอบใน MySQL 5.5.44 ดังนั้นเราสามารถหลีกเลี่ยงการแทรกหมายเลข 18446744073709551615

หมายเหตุ: ธุรกรรมทำให้แน่ใจว่าตัวแปร @rows นั้นสอดคล้องกับตารางที่พิจารณาในการดำเนินการคำสั่ง


ตามที่ @amd ระบุ: "เลือกจำนวน (*) บนโต๊ะที่มีระเบียน 7 ล้านรายการใช้เวลาประมาณ 17
วินาที

-1

ฉันรู้ว่านี่เก่า แต่ฉันไม่เห็นคำตอบที่คล้ายกันดังนั้นนี่คือวิธีแก้ปัญหาที่ฉันจะใช้

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

SELECT COUNT(*) FROM table_name;

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

SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;

หรืออาจเป็นไปได้ว่า:

SELECT * FROM table_name LIMIT desired_offset, count_result;

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


2
นับเลือก (*) บนโต๊ะที่มีประวัติ 7M เตะรอบ 17s
เอเอ็มดี

-7
WHERE .... AND id > <YOUROFFSET>

id สามารถเป็นคอลัมน์ตัวเลขที่เพิ่มอัตโนมัติหรือเฉพาะที่คุณมี ...


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