LIMIT kullanımı performansı artırır mı ve fark edilir mi?


11

Aşağıdakileri anlamak istiyorum.
Varsayalım karmaşık bir sorgu var diyelim bir grup 5 tablolar bir grup tarafından özetleri ve sıralama. Sorgu için herhangi bir optimizasyonun bir
kenara bırakılması, örneğin dizinler vb.
Kullanmanın önemli bir performans yararı var mı LIMIT? Tüm sorgu (ve sonuçları) LIMIT uygulanmadan önce işlenmesi gerektiğini varsayalım , bu yüzden sonuçların bir alt kümesini almak için bir LIMIT kullanarak, bu önemli / fark edilir bir gelişme sunuyor mu?


2
LIMITVerimliliği artıran durumlar için bunu okumanızı öneririm : LIMIT Sorgularını Optimize Etme
ypercubeᵀᴹ

Yanıtlar:


10

LIMITPerformansı artırmak için yararlanmak istiyorsanız ,

  • aldığınız verileri anlayın
  • doğru sütun dizilişinin doğru indekslenmesi
  • sorguyu yeniden düzenleme sorumluluğunu üstlenmek
  • daha LIMITönce kullanmakJOIN

Bu ilkeleri düzenleyebiliyorsanız uzun bir yol kat edebilirsiniz.

Bu kavramları bu YouTube videosunu izleyerek öğrendim (Fransız aksanıyla dikkatlice dinleyin)

Bazı kavramlardan ilk 40 makaleyi almakla ilgili çok zor bir StackOverflow sorusunu yanıtlamak için bu kavramları kullandım: 12 Mayıs 2011: Birleştirme tablosundan tek bir satır getiriliyor .

Bu soruya cevabımda (16 Mayıs 2011) , aşağıdaki sorguyu yazdım ve iyice test ettim:

SELECT
  AAA.author_id,
  AAA.date_created,
  IFNULL(BBB.title,'<NO_TITLE>') title,
  IFNULL(CCC.filename,'<NO-IMAGE>') filename,
  IFNULL(CCC.date_added,'<NO-IMAGE-DATE>') image_date
FROM
(
  SELECT
    AA.id,
    AA.date_added,
    BB.author_id,
    BB.date_created
  FROM
  (
    SELECT
      A.id,IFNULL(MAX(B.date_added),'1900-01-01 00:00:00') date_added
      FROM (SELECT id FROM articles ORDER BY date_created DESC LIMIT 40) A
      LEFT JOIN article_images B ON A.id = B.article_id
      GROUP BY A.id
  ) AA
  INNER JOIN articles BB USING (id)
) AAA
LEFT JOIN article_contents BBB ON AAA.id=BBB.article_id
LEFT JOIN article_images CCC
ON (AAA.id=CCC.article_id AND AAA.date_added=CCC.date_added)
ORDER BY AAA.date_created DESC;

Lütfen sorgudaki satırı LIMIT

      FROM (SELECT id FROM articles ORDER BY date_created DESC LIMIT 40) A

Bu alt sorgu üç seviye derinliğe gömüldü. Bu, kullanarak son 40 makaleyi almamı sağladı LIMIT. Sonra gerekli JOIN'leri daha sonra gerçekleştirdim.

DERSLER ÖĞRENİLDİ

  • Doing LIMITalt sorgular içeride hep çünkü endeksinin kardinalitesi, veri içeriği ve gelen sonuç kümesi boyutu cevabı olmayabilir LIMIT. Tüm "üst üste ördekler" varsa (Sorgunuz için dört prensibi göz önünde bulundurun), şaşırtıcı derecede iyi sonuçlar elde edebilirsiniz.
  • LIMITSadece anahtarları toplayarak sorgularınızı mümkün olduğunca basit hale getirin .

Yani (A [LEFT] JOIN B) LIMIT 100eşdeğer (A LIMIT 100) [LEFT] JOIN (B LIMIT 100)mi? [LEFT] JOINDış veya iç birleşim nerede
Jim

Daha çok benziyor (A LIMIT 100) [LEFT] JOIN B. Fikir, LIMITsonuç kümesinin boyutunu mümkün olduğunca erken belirlemek için kullanmaktır . Ben de kullanmak LEFT JOINyerine INNER JOIN, çünkü LEFT JOINsol tarafındaki tuşların düzeni koruyacaktır.
RolandoMySQLDBA

@Jim Hayır, değiller. Bazen, bunlar böyle: (A LEFT JOIN B) GROUP BY A.pk LIMIT 100genellikle yeniden yazılabilir (A LIMIT 100) LEFT JOIN B GROUP BY A.pk(burada INNER JOIN yok, iç birleşimlerle eşdeğer olmazlar.) Rolando'nun örneği tam olarak böyle bir durumdur.
ypercubeᵀᴹ

@ypercube: Öyleyse iç birleşimlerde LIMIT'den yararlanmak için yapacak bir şey yok mu?
Jim

Rolando tarafından özetlenen yeniden yazma stratejisinden bahsediyordum. JOIN ve LIMIT ile yapılan bir sorgu da fayda sağlayabilir. Ya da değil. Değişir.
ypercubeᵀᴹ

2

Bir sorgu yürütüldüğünde, önce birkaç operatörden oluşan bir plana çevrilir. İki temel operatör türü vardır: Engelleme ve Engellememe. Engellemeyen İşleç, kendisinden istenen her satır için alt satırından veya alt satırından bir satır (veya birkaç satır) alır. Öte yandan bir Engelleme İşleci, herhangi bir çıktı üretmeden önce tüm çocuklarının tüm satır kümesini okumalı ve işlemelidir.

Sıralama tipik bir Engelleme İşleci'dir. Yani sipariş ile bir seçim bir sınırdan fazla fayda sağlamaz. Ancak, daha az bellek gerektiren ve bir sınır yan tümcesi sağlandığında daha hızlı olan bir sıralama algoritması kullanabilen RDBMS'ler vardır. Bu durumda, şu anda ilk n satırı saklamak ve daha önceki satırlar geldikçe bunları bellekten çıkarmak yeterlidir. Bu önemli bir performans kazancı olabilir. Ancak, MySQL'in bu yeteneğe sahip olduğundan% 100 emin değilim.

Her iki durumda da, bir sınır sıralamasının bile ilk çıkış satırını üretmeden önce tüm girdi satırını işlemesi gerekir. Uygulanırsa, bu algoritma sıralamayı hızlandırabilirken, sorgunun geri kalanı en pahalı kısım ise, sağlanan çalıştırma sınırı nedeniyle toplam yürütme süresi önemli ölçüde iyileşmez.


Cevabı biraz kafam karıştı. Sıralamadan bahsediyorsun ama sırala grupla da değil mi? Örneğin, siparişi kaldırdım ve gruba bağlı kaldım, cevabınız hala geçerli mi? Yoksa farklı bir analiz mi gerekiyor?
Jim

Sorguya ve mevcut indekslere bağlı olarak, GROUP BYpotansiyel olarak engelleme operatörleri içermeyen bir plana yol açabilir.
Sebastian Meine

0

Benim durumumda, (hala) nedenini anlamamış olsam bile Evet diyebilirim .

SELECT g0_.id AS id_0, COUNT(a1_.id_tarifs) AS sclr_1
FROM groupe_jardinerie g0_
INNER JOIN articles_tarifs a1_
  ON (a1_.groupe_jardinerie_id = g0_.id)
WHERE g0_.centrale_id = 511
  AND a1_.date_fin_tarif >= '2018-01-29 10:46:35'
GROUP BY g0_.id;

(result set)

8 rows in set (**18.14 sec**)

Süreye dikkat edin: 18 saniye. Büyük bir LIMIT ile aynı istek:

SELECT g0_.id AS id_0, COUNT(a1_.id_tarifs) AS sclr_1 
FROM groupe_jardinerie g0_
INNER JOIN articles_tarifs a1_
  ON (a1_.groupe_jardinerie_id = g0_.id)
WHERE g0_.centrale_id = 511 
  AND a1_.date_fin_tarif >= '2018-01-29 10:46:35'
GROUP BY g0_.id
LIMIT 100000000000;

(exact same result set)

8 rows in set (**1.32 sec**)

On kat daha hızlı !!!

EXPLAIN her iki istek için de aynı sonucu verir.

+----+-------------+-------+------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+----------+----------------------------------------------+
| id | select_type | table | partitions | type   | possible_keys                                     | key     | key_len | ref                          | rows   | filtered | Extra                                        |
+----+-------------+-------+------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+----------+----------------------------------------------+
|  1 | SIMPLE      | a1_   | NULL       | ALL    | IDX_438010BBC10784EF                              | NULL    | NULL    | NULL                         | 795135 |    33.33 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | g0_   | NULL       | eq_ref | PRIMARY,IDX_9CA5CF6758A1D71F,IDX_9CA5CF67670C757F | PRIMARY | 4       | phs.a1_.groupe_jardinerie_id |      1 |    50.00 | Using where                                  |
+----+-------------+-------+------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+----------+----------------------------------------------+

LIMIT yalnızca sonuç kümesini sınırlamak için müdahale etmelidir (örn. LIMIT 4 yaparsam, yukarıdaki sonuç kümesinin yalnızca ilk 4 satırını aldım).


dehşet verici, hangi sürümü kullanıyorsunuz ve basitleştirilmiş bir test senaryosu oluşturabilir misiniz?
Evan Carroll

1
Cevabınız yeni bir fayda sağlamaz LIMIT. 1. sorgunuz bir sonuç kümesi vererek 18 saniye içinde çalışır. İkinci sorgudaki tüm veriler ilk sorgu nedeniyle zaten InnoDB arabellek havuzunda önbelleğe alınır, Bu nedenle elbette 2. sorgunun daha hızlı olması gerekir, mysql'yi yeniden başlatsanız bile, 1. sorguyu çalıştırın, mysql'yi yeniden başlatın ve 2. sorgu, aynı sonucu alırsınız. . Bunun için daha iyi bir sonuca sahip olmak LIMITsadece 1) LIMITöncesi JOIN, 2) LIMIT sıralama düzeninde ASCveya DESC.
RolandoMySQLDBA

İlginiz için teşekkür ederiz. Basitleştirilmiş bir test senaryosu oluşturmak zor olabilir.
Pierre-Olivier Vares
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.