2010-11-20 16 views
1

Kaybettim. Yaklaşık 100K satırlık bir tablom var. Bu tabloyu sorgularken sonuçlar genellikle 2 ms veya daha hızlıdır. Ancak, bir ORDER BY performansı kullandığımda, bir kaya gibi yaklaşık 120 ms'ye düşer. MySQL ORDER BY Optimization sayfasını okudum ama her şeyi anladığımı söyleyemem. Özellikle endeksler bana net değil.Bir ORDER BY sorgusunu en iyi duruma getirme

SELECT * 
    FROM `affiliate_new_contracts` 
WHERE phone_brand IN ('Apple','Blackberry','HTC','LG','Motorola','Nokia', 
         'Samsung','Sony Ericsson') 
    AND contract_length IN ('12','24') 
    AND (addon IS NULL OR addon IN('Telfort Sms 300','Surf & Mail')) 
    AND (plan_name = 'Telfort 100' 
     AND 
     credible_shop = 1 
     ) 
    ORDER BY average_price_per_month ASC, phone_price_guestimate DESC, 
      contract_length ASC; 

Ama altında yatan ilkeleri anlamış eğer mutlu olurdu:

Sonuçta ben aşağıdaki sorguyu çalıştırmak istiyorum.
Önceki sorgudaki ORDER BY deyiminin kaldırılması, 120 msn sonunda 20 ms'de çalışmasını sağlar. average_price_per_month alanında bir dizin var, ancak ORDER BY yan tümcesini ORDER BY average_price_per_month için basitleştirerek performans artışı sağlamadı. Anlamıyorum ki. Ayrıca nihai sorgu ile bana yardımcı olması gereken çok sütun indeksleri hakkında karanlıktayım.

Herhangi bir yardım için teşekkür ederiz. Bu kötü çocuğu nasıl gerçekleştiririm? Yoksa bu ütopyacı mı? aşağıdaki gibi

CREATE TABLE sözdizimi:

$ show create table affiliate_new_contracts; 
CREATE TABLE `affiliate_new_contracts` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `plan_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `contract_length` int(11) DEFAULT NULL, 
    `phone_brand` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `price` float DEFAULT NULL, 
    `average_price_per_month` float DEFAULT NULL, 
    `phone_price_guestimate` float DEFAULT NULL, 
    `credible_shop` tinyint(1) DEFAULT '0', 
    `addon` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `addon_price` float DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `index_affiliate_new_contracts_on_plan_name` (`plan_name`), 
    KEY `index_affiliate_new_contracts_on_average_price_per_month` (`average_price_per_month`), 
    KEY `index_affiliate_new_contracts_on_price` (`price`) 
) ENGINE=InnoDB AUTO_INCREMENT=2472311 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

BTW Bu tablo haftalık yeniden oluşturulur ve bu arada güncellenmiş değil.

+1

Yatay kaydırma çubuklarından kaçınmak için sorguyu yeniden biçimlendirdim. Sorguların son çifti (plan adı ve güvenilir dükkanda), sorgunun geri kalanıyla tutarsız bir şekilde yazılır (diğer terimler, tablo adını kullanmaz) ve etraflarındaki parantezlere gerçekten gerek duymaz. Yorum yapmadan düzeltip düzeltmeyeceğimi tartıştım ve karar vermemeye karar verdim. Bu terimleri tutarlı hale getirmeye karar verirseniz, bu yorumu kaldıracağım. –

+0

Mükemmel yorum. Sorgunun bir kısmı oluşturuldu/oluşturuldu (daha fazla kanıt, sorgular için çok uygun değil). Gereksiz tablo adını kaldırdım. – harm

cevap

3

ORDER BY cümlelerinde ne kadar optimizasyon yapabileceğiniz konusunda bir sınırlama vardır. Bazen yardımcı olan birincil şey doğru sırada doğru sütun kümesinde bir dizin bulundurmaktır. Yani, örneğin, bir (tek, birleşik) endeks üzerinde:

average_price_per_month ASC, phone_price_guestimate DESC, contract_length ASC 

yardımcı olabilir, ama iyileştirici hala sorguda filtre şartları ile başa çıkmak için başka bir dizin kullanmak daha olduğuna karar verebilir ve o zaman bu şekilde seçilen verileri sıralar. Dizin, verileri tam olarak sıralanan sıraya göre sağlamazsa ve dizinin kullanılması genel olarak sorguyu hızlandırmazsa, optimizatör onu kullanmayacaktır. Sıralanacak sütunlardan sadece birinde bulunan bir endeks, optimize edici için sınırlı bir avantajdır ve normalde böyle bir indeksi kullanmaz.

Bir soru dikkate almak:

  • Ne kadar hızlı sorgu ORDER BY deyimi olmadan performans gösteriyor.

Bu, sıralama maliyetinin çok doğrudan bir ölçümünü verir. Sipariş vermeden 20 ms ve sipariş verdiğinizde 120 ms'den bahsetmişsiniz, bu nedenle SİPARİŞ BY orta derecede pahalıdır. Bir sonraki soru "Kendi uygulamanızda sıralamadan daha iyi performans gösterebilir misiniz?" Bunu yapabileceksiniz, ancak bir DBMS'deki sıralama paketi genellikle oldukça iyi bir şekilde optimize edilmiş ve bunu geçmek için çok çalışmak zorunda kalacaksınız.

0

Dizininizin size iyi bir şey yapmadığından şüpheleniyorum çünkü birincil anahtar değil ve sorgu seçim mantığınız (burada madde) kullanmıyor. Çünkü hangi satırları seçmek için endeksi kullanmıyorsanız, sonuçları seçtikten sonra sıralamak zorunda kalıyorsunuz. Birincil anahtarınız olmadığı gerçeği, sonuçların ay başına ortalama fiyatla sıralanmadığı anlamına gelir. Bu da, sipariş verildikleri için sıralama zamanını azaltacak veya ortadan kaldıracaktır. Bir çözüm, en seçici sütunu (plan adı) ve sipariş sütununu (ortalama_price_per_month) içeren bir bileşik indeks kullanmak olacaktır.Seçimden sonra sıralama yapması gerekecek, ancak sonuçlar birincil sipariş sütunu tarafından harcanan süreyi kısaltarak sipariş edilecektir.

CREATE TABLE `affiliate_new_contracts` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `plan_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `contract_length` int(11) DEFAULT NULL, 
    `phone_brand` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `price` float DEFAULT NULL, 
    `average_price_per_month` float DEFAULT NULL, 
    `phone_price_guestimate` float DEFAULT NULL, 
    `credible_shop` tinyint(1) DEFAULT '0', 
    `addon` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `addon_price` float DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `index_affiliate_new_contracts_on_plan_name` (`plan_name`,`average_price_per_month`), 
    KEY `index_affiliate_new_contracts_on_price` (`price`) 
) ENGINE=InnoDB AUTO_INCREMENT=2472311 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

Ayrıca (benim sezgi doğru değilse) sorgu yapılırken anlamak EXPLAIN kullanabilir ve buna göre endekslerini ayarlamak isteyebilirsiniz.

İlgili konular