MySQL Data - Disk belleği uygulamanın en iyi yolu?


209

İPhone uygulamam, MySQL veritabanından veri almak için PHP web servisime bağlanıyor. Bir istek 500 sonuç döndürebilir.

Sayfalamayı uygulamanın ve aynı anda 20 öğeyi almanın en iyi yolu nedir?

Diyelim ki veritabanımdan ilk 20 reklamı aldım. Şimdi önümüzdeki 20 reklam için nasıl talepte bulunabilirim?

Yanıtlar:


309

MySQL belgelerinden :

LIMIT deyimi, SELECT deyimi tarafından döndürülen satır sayısını sınırlamak için kullanılabilir. LIMIT, her ikisi de negatif olmayan tamsayı sabitleri (hazırlanmış ifadeler kullanıldığında hariç) olması gereken bir veya iki sayısal bağımsız değişken alır.

İki argümanla, ilk argüman döndürülecek ilk satırın ofsetini ve ikincisi döndürülecek maksimum satır sayısını belirtir. İlk satırın ofseti 0'dır (1 değil):

SELECT * FROM tbl LIMIT 5,10;  # Retrieve rows 6-15

Belirli bir ofsetten sonuç kümesinin sonuna kadar tüm satırları almak için ikinci parametre için bir miktar büyük sayı kullanabilirsiniz. Bu ifade, 96. satırdan son satıra kadar olan tüm satırları alır:

SELECT * FROM tbl LIMIT 95,18446744073709551615;

Bir bağımsız değişkende, değer sonuç kümesinin başından döndürülecek satır sayısını belirtir:

SELECT * FROM tbl LIMIT 5;     # Retrieve first 5 rows

Başka bir deyişle, LIMIT row_count, LIMIT 0, row_count ile eşdeğerdir.


107
Disk belleği için LIMIT kullanırken ayrıca bir ORDER BY belirtmelisiniz.
Mark Byers

10
@shylent: Belgeleri alıntılamada yanlış bir şey yok, ancak belgeleri kopyaladığını ve orijinal kaynağa bir bağlantı sağladığını belirtmesi gerektiğini kabul ediyorum. Ayrıca, belgelerin SİPARİŞ VERMEDEN LİMİT kullanma örneklerini içereceğine şaşırdım ... cesaret verici bir uygulama gibi görünüyor. ORDER BY olmadan, siparişin aramalar arasında aynı olacağının garantisi yoktur.
Mark Byers

13
Büyük resultsets Sayfalara ayırma (ve hangi sayfalandırma o en içindir? - sağ, daha küçük parçalardan büyük resultsets break up) ne zaman neyse, size yaparsanız akılda tutmalı limit X, Y, aslında ne olur X + Y satırlar daha sonra alınan ve olmasıdır En başından X satır atılır ve kalan her şey döndürülür. Tekrarlamak için: limit X, YX + Y satırlarının taranmasıyla sonuçlanır.
shylent

7
LIMIT 95, 18446744073709551615 fikrinizi sevmiyorum .. OFFSET;-)
CharlesLeaf

5
Büyük verilerle çalışırken bu etkili değildir. Belirli senaryo için uygun olan birden fazla yol için codular.com/implementing-pagination adresini kontrol edin .
Amit

125

500 kayıt için verimlilik muhtemelen bir sorun değildir, ancak milyonlarca kayıt varsa, bir sonraki sayfayı seçmek için bir WHERE yan tümcesi kullanmak avantajlı olabilir:

SELECT *
FROM yourtable
WHERE id > 234374
ORDER BY id
LIMIT 20

Buradaki "234374", görüntülediğiniz önceki sayfadaki son kaydın kimliği.

Bu, ilk kaydı bulmak için kimlikteki bir dizinin kullanılmasını sağlar. Eğer kullanırsanız LIMIT offset, 20sonuna doğru sayfa gittikçe yavaşlar ve yavaşlar. Söylediğim gibi, muhtemelen sadece 200 kaydınız olması önemli değil, ancak daha büyük sonuç kümeleriyle fark yaratabilir.

Bu yaklaşımın bir diğer avantajı, çağrılar arasında veri değişmesi durumunda kayıtları kaçırmayacak veya tekrarlanan bir kayıt almayacaksınızdır. Bunun nedeni, bir satırın eklenmesi veya kaldırılmasının, tüm satırların kaydırıldıktan sonra kayması anlamına gelmesidir. Sizin durumunuzda muhtemelen önemli değil - sanırım reklam havuzunuz çok sık değişmiyor ve yine de hiç kimse aynı reklamı üst üste iki kez aldıklarını fark etmeyecekti - ama "en iyi yolu" arıyorsanız hangi yaklaşımın kullanılacağını seçerken akılda tutulması gereken başka bir şey budur.

LIMIT'i bir ofsetle kullanmak istiyorsanız (ve bir kullanıcı sayfalar tek tek sayfalamak yerine doğrudan sayfa 10000'e giderse bu gereklidir) , LIMIT'in performansını büyük bir oranla artırmak için geç satır aramaları hakkında bu makaleyi okuyabilirsiniz. ofset.


1
Bu daha çok şöyledir: P Ben imadan kesinlikle vazgeçmeme rağmen, 'yeni' kimlikler her zaman 'eski' olanlardan daha büyüktür, çoğu zaman bu durum böyle olur ve bence bu 'iyi' yeter'. Her neyse, evet, gösterdiğiniz gibi, uygun sayfalandırma (büyük limit 1000000, 10sonuç kümelerinde ciddi performans düşüşü olmadan) özellikle önemsiz değildir ve işe yarayacağını ummak ve yazmak umarım sizi hiçbir yere götürmez.
shylent

1
geç arama bağlantısı çok yararlı
pvgoddijn

1
Kimlik sıralaması için yalnızca "DESC" kullanırsanız, bu sayfalama geriye doğru çalışır. Bunu sevdim!
Dennis Heiden

2
ancak insanlar gerçek dünyada kimlikle veya aşağılama yoluyla "oluşturulma tarihi" ne kadar sık ​​sipariş vermek ister?
RichieHH

iyi gönderi, ancak area=width*heightbu sadece önemli olabilecek kayıtların miktarı değil, aynı zamanda her kaydın boyutu da sonuçları hafızada saklarken bir faktördür
hiçbir şey 19

43

Sorgu için OFFSET tanımlayın . Örneğin

sayfa 1 - (01-10 kayıtları): ofset = 0, sınır = 10;

sayfa 2 - (kayıtlar 11-20) ofset = 10, sınır = 10;

ve aşağıdaki sorguyu kullanın:

SELECT column FROM table LIMIT {someLimit} OFFSET {someOffset};

sayfa 2 için örnek:

SELECT column FROM table
LIMIT 10 OFFSET 10;

1
Şunu mu demek istedin offset = 10 için 2. sayfa?
Jenna Maiz

28

Bununla ilgili literatür var:

Asıl sorun büyük OFFSETs kullanımı ile olur . OFFSETMaddedeki idaralık seçimlerinden WHERE, bir tür önbellekleme veya bilgi işlem sayfalarına kadar çeşitli tekniklerle kullanmaktan kaçınırlar .

Use INDEX, Luke'da önerilen çözümler var :


1
Karmaşık sorguların her bir çağrı sorgusu için getiing max id pratik olmayan, üretim dışı kullanım sıralaması, satır numarası ve disk belleği yan tümce türü arasında sonuç ile sonuçlanır!
Rizwan Patel

Bu strateji dikkate alınmış ve sağlanan bağlantılarda uygun şekilde değerlendirilmiştir. O kadar da basit değil.
Luchostein

sağlanan bağlantı sadece temel pivot uni-pivot, çapraz uygulama, çoklu CTE veya türetilmiş masa mekaniği gibi görünüyor? yine maxid almak için tekrar böyle büyüklükte sorguları yeniden yazma ile benim durumumda durmak mimari overkill olduğunu! ve sonra tekrar sıralaması ile sütun sayısı n "için permütasyon ve kombinasyon!
Rizwan Patel

1
"Sayfalandırma doğru şekilde yapıldı" bağlantısını yanlış mı yoksa filtreleme içeren herhangi bir sorguda pratik değil mi?
contactmatt

1
@contactmatt Anladığınızı paylaşıyorum. Sonunda, tüm gereksinimi verimli bir şekilde uygulamanın bir yolu yok, ancak orijinalin etrafında rahat varyasyonlar var gibi görünüyor.
Luchostein


6

ayrıca yapabilirsin

SELECT SQL_CALC_FOUND_ROWS * FROM tbl limit 0, 20

Select deyiminin satır sayısı (sınırsız) aynı select deyiminde yakalanır, böylece tablo boyutunu tekrar sorgulamanız gerekmez. Satır sayısını SELECT FOUND_ROWS () kullanarak alırsınız;


1
Bu özellikle verimsizdir. *Daha zorunlu varlık getirilen daha sütunlar ve sonuçları SQL_CALC_FOUND_ROWSbu sütunlarda sonuçlarından okunduğunu tüm bunlar sonucunda dahil edilmemiştir rağmen tablosundaki satır. Tüm bu sütunları okumayan ayrı bir sorgudaki satır sayısını hesaplamak çok daha verimli olacaktır. Ardından, 20 satır okuduktan sonra ana sorgunuz durabilir.
thomasrutter

Emin misiniz? Ben sorgu büyük bir tablo SQL_CALC_FOUND_ROWS ve kullanmayan başka bir sorgu karşı zamanladı. Zaman farkı görmedim. Herhangi bir şekilde 2 sorgu yapmaktan daha hızlıdır. 1 - kabul edilebilir sınır 0 * 'dan * seçin ve sonra kabul edilebilir sayıdan (*) seçin.
surajz

1
Evet eminim - işte daha fazla bilgi . Her durumda satırları filtrelemek için bir dizin kullandığınızda, SQL_CALC_FOUND_ROWS 2 ayrı sorgu yapmaktan önemli ölçüde yavaştır. Nadiren bir dizin kullanmıyorsunuz veya (bu basitleştirilmiş örnekte olduğu gibi) WHERE yan tümcesi yok ve bu bir MYISAM tablosu, çok az fark yaratıyor (aynı hızda).
thomasrutter


4

Sorgu 1: SELECT * FROM yourtable WHERE id > 0 ORDER BY id LIMIT 500

Sorgu 2: SELECT * FROM tbl LIMIT 0,500;

Sorgu 1, küçük veya orta ölçekli kayıtlarla daha hızlı çalışır; kayıt sayısı 5.000 veya daha yüksekse, sonuç benzerdir.

500 kayıt sonucu:

Sorgu1 9.9999904632568 milisaniye alır

Sorgu2 19.999980926514 milisaniye alır

8.000 kayıt sonucu:

Sorgu1 129.99987602234 milisaniye alır

Sorgu2 160.00008583069 milisaniye alır


Bir indeks koymanız gerekiyor id.
Maarten

6
Nasıl id > 0faydalı?
Michel Jung

1
Maarten'ın dediği gibi, bu iki sorgu temel olarak aynı görünür ve muhtemelen her iki şekilde de aynı makine düzeyinde komutlara ayrılır. Bir indeksleme probleminiz veya MySQL'in gerçekten eski bir sürümü olmalıdır.
HoldOffHunger

teşekkürler, ben cevabınızı görmedim gibi, ben sadece nerede, sipariş ve sınır geliyor sipariş görmek gerekiyordu
Shreyan Mehta

yanlış örnek kullanılmıştır. ile offset(sınırlanacak ilk argüman ofsettir), yine de tüm verileri sınıra kadar seçersiniz, sonra ofsetin bu miktarını atarsınız, offsetve ile arasındaki bölümü döndürürsünüz limit. ile wherediğer taraftan maddesi, sorgu ve sorgu için bir başlangıç noktası bir tür ayarlarken ONLYbelirli bölümü söyledi.
senaps

0

Disk belleği, tek bir tablodan veri aldığında basittir, ancak birden çok tabloya katılan verileri aldığında karmaşıktır. MySql ve Spring için iyi bir örnek:
https://www.easycodeforall.com/zpagination1.jsp


Lütfen bir gün kaybolabilecek üçüncü taraf sitelerin bağlantılarını paylaşmayın. Yazarların sorusunu cevaplamak istiyorsanız, onlara yardımcı olması için ilgili kodu gönderin.
Markasız Manchester
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.