MySQL sonsuz satırları ofset


114

Tabloda tüm sonuçları görüntüleyen, ancak tablonun başlangıcından itibaren 5 kaydırılmış bir sorgu oluşturmak istiyorum. Anlayabildiğim kadarıyla, MySQL'ler LIMITbir sınır ve bir ofset gerektirir. Bunu yapmanın bir yolu var mı?


1
Bu tamamen geçerli bir soru, ancak merak ediyorum, her şeyi alıp programlı olarak ilk birkaç kaydı göz ardı etmek daha iyi olabilir mi? En iyi cevap gibi görünen şeyin dehşeti göz önüne alındığında (limit 5, 18446744073709551615), MySQL'in LIMIT'inin sınırlamaları etrafında çalışmayı büyük ölçüde tercih ederim.
cesoid

3
@cesoid ne istersen limit 5000, 18446744073709551615. Sadece kodunuzun güzel görünmesi için fazladan 5000 satır getirmeyeceksiniz.
elipoultorak

@ user3576887 Sanırım haklısınız, yukarıdaki soruyu, çok daha büyük olabilecek (ve başka birinin problemini çözmek yerine) değişen bir miktar yerine 5'in tek şart olduğu varsayımıyla düşünüyordum.
cesoid

Bunun o kadar nadir bir görev olduğunu ve çözümün çirkinliğinin kabul edilebileceğini düşünüyorum.
Rick James

Yanıtlar:


152

Gönderen LIMIT üzerinde MySQL Kılavuzuna :

Sonuç kümesinin sonuna kadar belirli bir uzaklıktan tüm satırları almak için, ikinci parametre için biraz büyük sayı kullanabilirsiniz. Bu ifade, 96. satırdan son satıra kadar tüm satırları alır:

SELECT * FROM tbl LIMIT 95, 18446744073709551615;

105
Korkunç! Buraya MySQL'in Limit cümlesini olduğu gibi isteğe bağlı yaptığını umarak geldim, ama aynı zamanda sağlanan bir ofsetle ... ama hayır! Bu 18446744073709551615'in kodun her tarafına dağıldığını gördüm ve tembel programcıları suçluyordum, ama bu bir tasarım özelliği!
Petruza

8
berbat cevap, ancak bu MySQL Doc'tan resmi. Ne diyebilirim @ _ @
GusDeCooL

21
18446744073709551615 merak edenler için 2 ^ 64-1'dir. Dikkat etmek isteyebilirsiniz çünkü bu değeri 32 bitlik bir tamsayıda saklayamayacaksınız. Uyumluluğu sağlamak için bunu bir dizge olarak sakladığınızdan emin olmalısınız.
AlicanC

13
Korkunç! bundan daha zarif olmaları gerekiyor ... Limit -1veya Limit Nulloldukça makul görünüyorlar! veya en azından Limit,select * from table limit (select count(*) from table)
vulcan raven

19
taşma efektlerinden kaçınmak için php 'PHP_INT_MAX' kullanın.
Karl Adler

24

Bahsettiğiniz gibi LIMIT gereklidir, bu nedenle mümkün olan en büyük sınırı, yani 18446744073709551615'i (maksimum imzasız BIGINT) kullanmanız gerekir.

SELECT * FROM somewhere LIMIT 18446744073709551610 OFFSET 5

33
Vay canına, bu MySQL ekibinin resmi çözümü mü?
Antony

12

Diğer yanıtlarda belirtildiği gibi, MySQL sınırdaki kayıt sayısı olarak 18446744073709551615 kullanılmasını önerir, ancak şunu düşünün: 18.446.744.073.709.551.615 kaydı geri alırsanız ne yapardınız? Aslında 1.000.000.000 kaydınız olsa ne yapardınız?

Belki bir milyardan fazla kayıt istiyorsunuz, ama benim açımdan, istediğiniz sayının bir sınırlaması var ve 18 kentilyondan az. Kararlılık, optimizasyon ve muhtemelen kullanılabilirlik adına, sorguya anlamlı bir sınır koymanızı öneririm. Bu aynı zamanda, o büyülü görünümlü sayıyı hiç görmemiş olan ve aynı anda en azından kaç kaydı ele almak istediğinizi iletme avantajına sahip olan herkes için kafa karışıklığını da azaltacaktır.

Veritabanınızdan gerçekten 18 kentilyon kaydın tamamını almanız gerekiyorsa, belki de gerçekten istediğiniz şey onları 100 milyonluk artışlarla alıp 184 milyar kez döngü yapmaktır.


Haklısınız, ancak bu kararı geliştiriciye vermek iyi bir seçim değil
amd

@amd Bunu biraz daha açıklar mısınız? Ne söylemeye çalıştığını bilmiyorum.
cesoid

1
@cesoid Sanırım devs'in benim de hemfikir olduğum iş mantığını keyfi olarak seçmesi gerektiğini söylüyor, ama sadece bir noktaya kadar. Bir müşteriye bir sipariş listesi iade ettiğinizi varsayalım. Bir seferde diyelim ki bir milyondan fazlasını asla geri döndürmemek tamamen mantıklıdır, ancak 100 ile sınırlandırılması kafa karışıklığına neden olabilir.
Sonbahar Leonard

@amd 18446744073709551615'i kullanmaktan kaçınmak için geliştiricinin uygulamanın davranışını değiştirmesi gerektiğini söylemiyorum. İstemci veya arayüz tasarımcısı ne olursa olsun uygulamanın bir parçası olarak bu numarayı kullanmanın mantıklı olup olmadığını düşünmeleri gerektiğini söylüyorum. talep etti ve herhangi bir şey için doğru uygulama olma ihtimalinin çok düşük olduğunu. MySQL kullanma kararı muhtemelen geliştirici tarafından 18 kentilyondan fazla bir şey olup olmayacağını sormadan verilmişti.
cesoid

5

Diğer bir yaklaşım, otomatik olarak artırılmış bir sütun seçmek ve ardından HAVING kullanarak filtre uygulamak olabilir.

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

Ama muhtemelen yüksek limit yaklaşımına bağlı kalırım.


teşekkür ederim ve merak ediyorum böyle bir sorguyu PHP ifadesine nasıl ekleyebilirim! böyle demek istiyorum$sql = 'SET @a :=0 SELECT .....';
Reham Fahmy

2

Diğerlerinin de bahsettiği gibi, MySQL kılavuzundan. Bunu başarmak için, işaretsiz bir büyük int'in maksimum değerini, yani bu korkunç sayıyı (18446744073709551615) kullanabilirsiniz. Ancak bunu biraz daha az karmaşık hale getirmek için tilde "~" bitsel operatörü kullanabilirsiniz.

  LIMIT 95, ~0

bitsel bir olumsuzlama olarak çalışır. "~ 0" sonucunun sonucu 18446744073709551615'tir.


1
MariaDB 10.3'te çalışmıyor :( LIMIT 5, ~0LIMIT ~0 OFFSET 5
İkisini

1
Bu MySQL 5.7'de bir şey değil - geçersiz sözdizimi.
Jonny Nott

0

Daha bugün bir mysql tablosundan büyük miktarda veri (bir milyon satırdan fazla) almanın en iyi yolunu okuyordum. Bunun bir yolu, önerildiği gibi , ofsetin LIMIT x,ynerede xolduğunu ve ydöndürülmesini istediğiniz son satırı kullanmaktır. Ancak, öğrendiğim gibi, bunu yapmanın en verimli yolu bu değil. Bir otomatik artış sütununuz varsa, hangi kayıttan başlamak istediğinizi belirten bir SELECTcümle içeren bir ifadeyi kolayca kullanabilirsiniz WHERE.

Örneğin, SELECT * FROM table_name WHERE id > x;

Görünüşe göre mysql, kullandığınızda tüm sonuçları alıyor LIMITve sonra yalnızca ofsete uyan kayıtları gösteriyor: performans için en iyisi değil.

Kaynak: Bu sorunun cevabı MySQL Forumları . Unutmayın, soru yaklaşık 6 yaşında.


13
Bir kaydı sildiyseniz, bu yanlış sonuçlar verecektir. Bu yöntem özellikle tehlikelidir, çünkü çoğu zaman işe yarar ve çalışmadığında sessizce başarısız olur.
Ekim 15'14

0

LIMIT ile bir MySQL ifadesi kullanabilirsiniz:

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'te test edilmiştir. Böylece, 18446744073709551615 sayısının eklenmesini önleyebiliriz.

not: işlem, @rows değişkeninin, ifadenin yürütülmesinde dikkate alınan tabloya uygun olmasını sağlar.


@amd'nin belirttiği gibi: "7M kayıtları olan bir tablodaki sayıyı (*) seçin
saniye

-1

Bunun eski olduğunu biliyorum ama benzer bir yanıt görmedim, bu yüzden kullanacağım çözüm bu.

İlk olarak, kaç tane kaydın var olduğunu görmek için tabloda bir sayma sorgusu yürütürdüm. Bu sorgu hızlıdır ve normalde yürütme süresi ihmal edilebilir. Gibi bir şey:

SELECT COUNT(*) FROM table_name;

Ardından, sorgumu sınırım olarak sayımdan aldığım sonucu kullanarak oluşturardım (çünkü bu, tablonun dönebileceği maksimum satır sayısıdır). Gibi bir şey:

SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;

Veya muhtemelen şöyle bir şey:

SELECT * FROM table_name LIMIT desired_offset, count_result;

Elbette, gerekirse, limit olarak sağlanacak gerçek, doğru bir değer elde etmek için, istenen_ offset'i count_result'tan çıkarabilirsiniz. Sağlamak için uygun bir sınır belirleyebilirsem, "18446744073709551610" değerini geçmek bir anlam ifade etmez.


2
7 milyon kayıtları olan bir tablodaki sayımı (*) seçin yaklaşık 17 saniye sürer
amd

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

id, sahip olduğunuz herhangi bir otomatik artırılmış veya benzersiz sayısal sütun olabilir ...


7
Kötü bir fikir. Bir satırı sildiyseniz yanlış ofset verecektir.
Ekim 15'14
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.