MySQL: Satır sayısını saymanın en hızlı yolu


117

MySQL'de birkaç satırı saymanın hangi yolu daha hızlı olmalıdır?

Bu:

SELECT COUNT(*) FROM ... WHERE ...

Veya alternatif:

SELECT 1 FROM ... WHERE ...

// and then count the results with a built-in function, e.g. in PHP mysql_num_rows()

Bu açıkça bir veritabanı bölgesi olduğundan ve veritabanı motorunun böyle şeyleri dahili olarak belirlerken herkesten daha hızlı olması gerektiğinden, ilk yöntemin daha hızlı olması gerektiğini düşünebiliriz.


1
Oh, benzer bir soru buldum ( stackoverflow.com/questions/1855226/… ). Ama sonra kullanıyorum SELECT 1ve kullanmıyorum SELECT *. Bir fark var mı?
Franz

bilmiyorum, ancak bu iki cevabın aynı olduğu düşünülebilir - mysql sorgu iyileştiricisi her birinde aynı şeyi yapabilir. birincisinin ikincisinden daha az belirsiz olduğunu söyledi. neden bazı kriterler yazıp test etmiyorsunuz?
Jesse Cohen

Uhm, benzer bir soruyu farklı kelimelerle sorarak SO'nun arama motoru görünürlüğünü artırmaya çalıştığımı varsayalım;)
Franz

1
Aradaki fark, PHP tarafına gönderilen veri miktarıdır. Ne kadar çok sütununuz olursa, SELECT *, SELECT 1'e göre daha yavaş olur, çünkü sadece 1 sayısı yerine tüm sütunlar alınır mysql_query(). Örneğin, çalıştırdığınızda , sonuç kümesinin tamamı, siz ne olursa olsun MySQL'den PHP'ye gönderilir. bu verilerle yapın.
toon81

Bunun gibi bir soru sormak, içgörü veya yeni fikirler edinmenin harika bir yoludur, ancak sonuçta daha fazla hız istediğiniz belirli bir senaryonuz varsa, en hızlı olanı görmek için testler yapmanız gerekecektir.
still_dreaming_1

Yanıtlar:


125

Ne zaman COUNT(*)o sayısı, sütun endeksler alır, bu yüzden en iyi sonuç olacaktır. MyISAM motorlu Mysql aslında satır sayısını depolar, tüm satırları her saymaya çalıştığınızda tüm satırları saymaz. (birincil anahtarın sütununa göre)

Satırları saymak için PHP'yi kullanmak çok akıllıca değildir çünkü mysql'den php'ye veri göndermeniz gerekir. Mysql tarafında aynısını elde edebildiğinizde neden yapasınız?

Eğer COUNT(*)yavaş, çalıştırmak gerektiğini EXPLAINsorguya ve endeksler gerçekten kullanılırsa kontrol ve nerede eklenmelidir.


Aşağıdakiler en hızlı yol değildir , ancak COUNT(*)gerçekten uymayan bir durum vardır - sonuçları gruplamaya başladığınızda, COUNTtüm satırları gerçekten saymayan bir problemle karşılaşabilirsiniz .

Çözüm şudur SQL_CALC_FOUND_ROWS. Bu genellikle satırları seçerken kullanılır, ancak yine de toplam satır sayısını bilmeniz gerekir (örneğin, sayfalama için). Veri satırlarını seçtiğinizde, SQL_CALC_FOUND_ROWSanahtar kelimeyi SELECT'ten sonra eklemeniz yeterlidir:

SELECT SQL_CALC_FOUND_ROWS [needed fields or *] FROM table LIMIT 20 OFFSET 0;

Gerekli satırları seçtikten sonra, bu tek sorgu ile sayıyı alabilirsiniz:

SELECT FOUND_ROWS();

FOUND_ROWS() veri seçme sorgusundan hemen sonra çağrılmalıdır.


Sonuç olarak, her şey aslında kaç girişiniz olduğuna ve WHERE ifadesinde ne olduğuna bağlıdır. Çok sayıda satır olduğunda (onbinlerce, milyonlarca ve üstü) dizinlerin nasıl kullanıldığına gerçekten dikkat etmelisiniz.


14
Düzeltme: MyISAMsatır sayısını saklar. Diğer depolama motorları gibi InnoDB değil satır sayılarını depolamak ve tüm satırları her zamanı sayar .
The Scrum Meister

1
Bir satır olup olmadığını öğrenmek istediğinizde hangisinin en hızlı olacağını biliyor musunuz: SELECT 1 FROM ... LIMIT 1veya SELECT COUNT(*) FROM ...?
Franz

1
Verilere yine de ihtiyacınız varsa ve yalnızca sayfalandırma / vb. İçin bir sayı istiyorsanız, muhtemelen not etmek yararlıdır. Verileri almak ve ardından programınızdaki satırları saymak daha verimlidir.
Tyzoid

6
Motorun satır sayılarını depolayıp depolamaması önemli değildir. Soru açıkça bir WHEREcümle olduğunu belirtir .
Álvaro González

1
@Franz SELECT COUNT(*) FROM ..., neyin taranması gerektiğine bağlı olarak önemli ölçüde zaman alabilir (örneğin, çok büyük bir tablo veya milyon / milyarlar / trilyon satırlık bir dizin). SELECT 1 FROM ... LIMIT 1ilk satırla sınırladığınız için hemen döner.
jbo5112

59

Takım arkadaşlarımla konuştuktan sonra, Ricardo bize daha hızlı yolun olduğunu söyledi:

show table status like '<TABLE NAME>' \G

Ancak sonucun kesin olmayabileceğini unutmamalısınız.

Komut satırından da kullanabilirsiniz:

$ mysqlshow --status <DATABASE> <TABLE NAME>

Daha fazla bilgi: http://dev.mysql.com/doc/refman/5.7/en/show-table-status.html

Ve mysqlperformanceblog'da eksiksiz bir tartışma bulabilirsiniz


2
InnoDB için bu bir yaklaşımdır.
Martin Tournoij

2
Bu, sayımın (*) kelimenin tam anlamıyla saatler alabileceği çok büyük tablolardaki satır sayısı hakkında kabaca bir fikre ihtiyaç duyduğunuzda bilmek harika!
Mark Hansen

Bu beni tüm tüylerimi çekmekten kurtardı. COUNT (*), veritabanımdaki 33 milyon artı satırı saymak için yaş alıyordu. Her neyse, yalnızca paralelleştirilmiş satırları silme işlevimin çalışıp çalışmadığını bilmek istedim. Tam bir sayıya ihtiyacım yoktu.
joemar.ct

1
+1 Bunun yerine tablo durumunu kullanmak "COUNT (*)" bu soruya "en hızlı" değil, "doğruluk" ile ilgili doğru cevap olmalıdır.
lepe

2
Kullanılması SHOW TABLE STATUS(veya eşdeğeri SELECTiçinde information_schema) hızlı, ama bir işlemez WHEREmaddesini. MyISAM için kesin, ancak InnoDB için kesin değil (bazen 2 katına çıkıyor).
Rick James

29

Harika soru, harika cevaplar. Biri bu sayfayı okuyorsa ve bu bölümü kaçırıyorsa, sonuçları yansıtmanın hızlı bir yolu:

$counter = mysql_query("SELECT COUNT(*) AS id FROM table");
$num = mysql_fetch_array($counter);
$count = $num["id"];
echo("$count");

5
mysql_query, PHP 5.5.0 itibariyle kullanımdan kaldırılmış bir işlevdir.
Omar Tariq

8
Neden olmasın as count? idilk bakışta kafa karıştırıcı.
Orkhan Alikhanov


17

Bu sorgu ( bayuah'ın gönderdiklerine benzer ) bir veritabanındaki tüm tabloların güzel bir özetini gösterir: ( kesinlikle tavsiye ettiğim Ivan Cachicatari tarafından saklı yordamın basitleştirilmiş sürümü ).

SELECT TABLE_NAME AS 'Table Name', TABLE_ROWS AS 'Rows' FROM information_schema.TABLES WHERE TABLES.TABLE_SCHEMA = '`YOURDBNAME`' AND TABLES.TABLE_TYPE = 'BASE TABLE'; 

Misal:

+-----------------+---------+
| Table Name      | Rows    |
+-----------------+---------+
| some_table      |   10278 |
| other_table     |     995 |

Bana bir sonuç veriyor. Ancak count (1) ve bu farklı sonuçlardan elde edilen sonuçlar. Bu yol, her zaman say sorgusundan daha az sayı verir. Düşüncesi olan var mı?
Ayyappan Sekar

3
Okuyuculara sadece bir not. Bu yöntem son derece hızlıdır, ancak yalnızca yaklaşık satır sayısıyla çalışabildiğinizde uygulanabilir çünkü depolanan değer information_schema, SELECT count(*) FROMInnoDB kullanılması durumunda döndürülen değerle aynı değildir . Kesin bir değere ihtiyacınız varsa, bu yöntemin yalnızca MyISAM tablolarında kesin değer verdiğini unutmayın. InnoDB ile satır sayısı kabaca yaklaşıktır.
Bartosz Firyn

13

Aşağıdakilerin bana en hızlı yanıt sürelerini vereceğini her zaman anladım.

SELECT COUNT(1) FROM ... WHERE ...

1
ŞUNLARDAN 1'i SEÇİN ... NEREDE ... daha da hızlı olmaz mı?
patrick

3
@patrick - SELECT 1 ...sayıda satır olarak dönecektir WHEREve LIMITsormak ve hepsi "1" olacaktır.
Rick James

1
show table status like '<TABLE NAME>' Bu çok daha hızlı olacak.
derin

@deep - ancak bir maddeniz varsa alakalı değildir WHERE. Ve InnoDB için bu yalnızca bir tahmindir.
Rick James

@RickJames evet doğru!
derin

6

Sonuç kümesinin tamamının sayısını almanız gerekiyorsa, aşağıdaki yaklaşımı uygulayabilirsiniz:

SELECT SQL_CALC_FOUND_ROWS * FROM table_name LIMIT 5;
SELECT FOUND_ROWS();

Bu, normalde kullanmaktan daha hızlı değildir, COUNTancak bunun tersi olduğunu düşünebilirsiniz, çünkü hesaplamayı dahili olarak yapıyor ve verileri kullanıcıya geri göndermiyor, bu nedenle performans iyileştirmesinden şüpheleniliyor.

Bu iki sorguyu yapmak, toplamları almak için sayfalandırma için iyidir, ancak özellikle WHEREcümle kullanmak için değildir .


Intersting. Bu, en yaygın veritabanı sistemlerinde çalışıyor mu? MySQL, Postgres, SQLite ...?
Franz

4
Bu aslında çoğu zaman COUNT (*) kullanmaktan daha hızlı değildir. Stackoverflow.com/questions/186588/… sayfasına
toon81

2
Bu işlevi kullanırken ÇOK dikkatli olmalısınız. Bir zamanlar pervasız kullanımı, tüm üretim ortamımızı öğütme durma noktasına getirdi. ÇOK yoğun kaynak gerektirir, bu nedenle dikkatli kullanın.
Janis Peisenieks

6

Bazı kriterler yaptığı çalışma süresini karşılaştırmak COUNT(*)vs COUNT(id)(- endeksli id tablonun birincil anahtardır).

Deneme sayısı: 10 * 1000 sorgu

Sonuçlar: COUNT(*)% 7 daha hızlı

GRAFİĞİ GÖRÜNTÜLE: kıyaslama

Benim tavsiyem şunu kullanmaktır: SELECT COUNT(*) FROM table


1
Bilginize COUNT(1),
saymanın

4

Bunu dene:

SELECT
    table_rows "Rows Count"
FROM
    information_schema.tables
WHERE
    table_name="Table_Name"
AND
    table_schema="Database_Name";

@lepe Üzgünüm. Demek istediğim, olumsuz oy kullanan birinin bunu neden yaptığına dair bir açıklama yapması çok güzel, böylece herkes bu konuda bir şeyler öğrenebilir.
bayuah

1
Bu size hızlı bir şekilde yaklaşık bir cevap verecektir . Kesin bir cevaba ihtiyacınız varsa, performans göstermeniz select count(*) from table_nameveya başka bir şey yapmanız gerekir . dba.stackexchange.com/questions/151769/…
Programster

@Programster Teşekkürler. Beni neredeyse bir yıl karanlıkta bırakmaktan daha iyi.
bayuah

1
@bayuah Son yorumunuzla ne demek istediğinizden emin değilim. Sadece cevabını reddeden kişinin ben olduğumu düşündüğünü varsayabilirim, ki ben değilim.
Programster

1
@Programster Hayır, üzgünüm, bunu demek istemedim. Açıklamanız için teşekkür etmek istedim, böylece Downvoter'ın bunu yaptığında belki de ne düşündüğünü tahmin edebilirim.
bayuah

3

Belki bir SELECT max(Id) - min(Id) + 1. Bu yalnızca kimlikleriniz sıralıysa ve satırlar silinmemişse çalışır. Ancak çok hızlı.


3
Dikkatli olun: sunucular bazen otomatik artış değeri> 1 kullanır (yedekleme nedenleriyle), bu nedenle bu çözüm iyidir, ancak önce DB yapılandırmanızı kontrol etmelisiniz.
Alex

1

EXPLAIN SELECT id FROM ....benim için hile yaptı. ve rowssonuç sütununun altındaki satır sayısını görebiliyordum .


0

Bazen 60 milyon kayıtla Alman Hükümeti için tablolarla ilgileniyordum.

Ve toplam satırları birçok kez bilmemiz gerekiyordu.

Bu yüzden biz veritabanı programcıları, her tabloda bir kayıt olduğuna karar verdik, her zaman toplam kayıt numaralarının saklandığı kayıt. INSERT veya DELETE satırlarına bağlı olarak bu numarayı güncelledik.

Diğer tüm yolları denedik. Bu açık arayla en hızlı yoldur.


1
ve bu satırı nasıl güncellediğinizin ayrıntıları nelerdir? Bu, tüm satırların sürüş için boşa harcanmış bir int gerektirdiği bir tablo için hatalı bir tasarım anlamına gelir.
Drew

5
Evet, bu gerçekten aptalca haha. Her sorguda ilk satırı görmezden gelmelisiniz. Yalnızca bir toplamlar tablosu oluşturur ve bunu bir tetikleyiciye göre doldururdum. Kullanıcı tablosu ekleme, güncelleme toplamları tablosu. Silme, güncelleme toplamları tablosundaki kullanıcılar tablosu.
HTMLGuy

-1

Birincil anahtardaki koşullu bir count (*) ifadesi, tam tablo taramasından kaçınarak benim için satır sayısını çok daha hızlı döndürdü.

SELECT COUNT(*) FROM ... WHERE <PRIMARY_KEY> IS NOT NULL;

Bu benim için çok daha hızlıydı

SELECT COUNT(*) FROM ...
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.