MySQL'de, WHERE yan tümcesindeki sütunların sırası sorgu performansını etkiler mi?


38

Büyük olası sonuç kümeleri olan bazı veritabanı sorgularında performans sorunları yaşıyorum.

Söz konusu sorgu AND, NERED cümlede üç tane var

Maddelerin sırası önemli mi?

Gibi, önce ASI_EVENT_TIME yan tümcesini koyarsam (bu, sonuçların çoğunu herhangi bir maddenin dışına çıkarır.

Bu sorgu üzerinde çalışma süresini artıracak mı?

SORGU:

SELECT DISTINCT  activity_seismo_info.* 
FROM `activity_seismo_info` 
WHERE 
    activity_seismo_info.ASI_ACTIVITY_ID IS NOT NULL  AND 
    activity_seismo_info.ASI_SEISMO_ID IN (43,44,...,259) AND 
    (
        activity_seismo_info.ASI_EVENT_TIME>='2011-03-10 00:00:00' AND 
        activity_seismo_info.ASI_EVENT_TIME<='2011-03-17 23:59:59'
    ) 

ORDER BY activity_seismo_info.ASI_EVENT_TIME DESC

Sorgunun EXPLAIN:

+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
| id | select_type | table   | type  | possible_keys             | key          | key_len | ref  | rows  | Extra                       |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
|  1 | SIMPLE      | act...o | range | act...o_FI_1,act...o_FI_2 | act...o_FI_1 | 5       | NULL | 65412 | Using where; Using filesort |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+

Kullanımı:

PHP 5.2

MySQL 5.0.51a-3ubuntu5.4

Propel 1.3

Symfony 1.2.5


SİPARİŞ BY muhtemelen ne kadar uzun sürüyor. "Filesort kullanmak" oldukça yavaş olabilir. Uygulama mantığında SİPARİŞ BY kullanarak daha hızlı bir LOT sipariş yaparken buldum.
maclema

Aynı soruyu bir süre önce (bu siteden önce) stackoverflow'ta sordum. Orada aldığım cevaplar için bağlantıları kontrol edin. stackoverflow.com/questions/3805863/…
Scott

2
@maclema - Uygulamanız veritabanınızdan çok daha hızlı bir makinede çalışıyorsa, uygulamanızdaki tüm bu sıralama mantığının anlamsız yükünden bahsetmek yerine iddianız kesinlikle doğru değildir. order byveritabanına aittir.
Jack Douglas

Yanıtlar:


24

Ben öyle düşünmüyorum. Sorgu en iyi duruma getiricisi yeterince akıllı olmalıdır.

WHERE yan tümcelerini yeniden düzenlemeyi deneyebilir ve EXPLAINS'in her durumda size aynı şeyi söylediğini görebilirsiniz.


Bu sorguyu optimize etmek için neler yapılabilir: ASI_EVENT_TIME'da bir dizin var mı? (Bu sorguyu düşünüyorum da, sonuçları kullanarak sıraladığınız için en önemli şey bu).

Diğer iki alanda indeks var mı (ASI_SEISMO_ID ve ASI_ACTIVITY_ID)?

Tablo yapısını yayınlarsanız yardımcı olur.


Etkinlik zamanlarının bir dizinini oluşturmayı hiç düşünmedim. Bunu yarın dev bir db üzerinde deneyeceğim ve gözle görülür bir fark olup olmadığını göreceğim.
Patrick

@Patrick Bu dizini kullanacak diğer tüm sorguların bu tarihi azalan sırayla verdiğini varsayarsak, dizin anahtarını (activity_seismo_info.ASI_EVENT_TIME) azalan sırayla da sipariş etmek istersiniz.
Matt M

@MattM Bir indeks anahtarı sipariş edebileceğinizi bilmiyordum. Awesome İndeks anahtarını sipariş edersem, bunun tersine performans indeks anahtarınınkinden daha kötü olmadığı noktaya gelmesi zorunlu olur mu?
Patrick

@Patrick Haklısın. Beynim SQL Server ülkesinde kaldı. Sıralama düzenini MYSQL'de belirleyebilirsiniz ve ayrıştırır, ancak dikkate alınmaz. MYSQL'de tüm endeksler artan sırada sıralanmıştır. Karışıklık için özür dilerim.
Matt M

13

Gönderen belgeler :

Tablonun çok sütunlu bir dizini varsa, dizinin en soldaki öneki, satırları bulmak için en iyileştirici tarafından kullanılabilir. Örneğin, üzerinde üç sütunlu bir dizininiz varsa (col1, col2, col3), (col1), (col1, col2) ve (col1, col2, col3) üzerinde indekslenmiş arama yetenekleriniz vardır.

Sütunlar dizinin en sol önekini oluşturmazsa MySQL bir dizin kullanamaz.

Bu yüzden evet, bileşik dizindeki sütunların sırası ile aynı olmalıdır .


4
Tablonun solundaki sütunları seçen çoklu sütun dizini varsa - ancak seçtiğiniz sıra önemli değildir. Bu yüzden eğer a, b, c WHERE c = 'foo' AND a = 'bar' AND b = 'foobar'indeksine sahipseniz bunu yaparsınız ve indeks yine de kullanıma uygundur.
16'da

10

Hayır, önemli değil.

Optimizer, SQL'i ayrıştırdıktan hemen sonra bir sürü basit dönüşüm yapar - bu onlardan biri.


8

Foo ve bar NEREDE

aynısını optimize eder

NEREDE bar VE foo

Ancak,

NEDEN eşit değil # 1 VE eşit değil # 2

Her iki parça da optimize edilemiyor. Örneğin,

1 ve 3 ARASINDAKİ VE B> 17

INDEX (a, b) veya INDEX'i (b, a) iyi şekilde kullanamazsınız

Farklı ifade etmek için, WHERE yan tümcesinde birlikte herhangi bir '=' testi AND'd birlikte kullanılır, sonra bir '-' olmayan '(IN, BETWEEN,>, vb.) Kullanılabilir. Birden fazla etkili bir şekilde optimize edilemez.

Sorgunuzda 3 madde var.

Görünüşe göre, INDEX (EVENT_TIME) muhtemelen en kullanışlıdır - AND'lerden birine yardım edecektir ve ORDER BY için "filesort" dan kaçınmak için kullanılabilir.

Eğer yinelenen bir satır yoksa (neden halt olur ki?), DISTINCT'den kurtulun. Bu daha fazla çabaya neden olur.

Lütfen performansla ilgili sorular sorarken SHOW CREATE TABLE 'ı ve TABLO DURUMUNU GÖSTER' 'seçeneğini belirtin.

Güncelle ... Yeni sürümler (örneğin, MySQL 5.7), bazı durumlarda IN( list of constants )neredeyse olduğu gibi davranabilir =. Güvenli oynamak için, bu sıraya uyun (her kısım isteğe bağlıdır):

  1. Herhangi bir sayı =.
  2. Bazı INs.
  3. En fazla bir aralıkta.

1

Optimizasyon belgesinin dediği MySQL :

Okunabilirliği feda ederken, aritmetik işlemleri daha hızlı hale getirmek için sorgularınızı yeniden yazmak isteyebilirsiniz. Çünkü MySQL otomatik olarak benzer optimizasyonlar yapar , sık sık bu işi önlemek ve bir daha anlaşılır ve sürdürülebilir biçimde sorgu bırakabilir. MySQL tarafından gerçekleştirilen optimizasyonlardan bazıları:

  • ...

  • Bir birleşimdeki her tablo için, tablo için hızlı bir NEREDE değerlendirmesi yapmak ve ayrıca en kısa zamanda satırları atlamak için daha basit bir NEREDE yapılır .

  • Her tablo dizini sorgulanır ve en iyi dizin, en iyi duruma getirici bir tablo taraması kullanmanın daha verimli olduğuna inanmıyorsa kullanılır . Bir kerede, en iyi endeksin tablonun% 30'undan daha fazla olmasına bakılmaksızın taranan bir tarama kullanıldı, ancak sabit bir yüzde artık bir indeks kullanmak ya da tarama arasında seçim yapmayı belirlemedi. Şimdi en iyileştirici daha karmaşıktır ve tahminini tablo boyutu, satır sayısı ve G / Ç blok boyutu gibi ek faktörlere dayandırır.

Bu şekilde, sorgu optimizerinin NASIL-sırasını atlaması rasyoneldir. Sorgudaki sütunları kullandık (Sadece MySQL değil, SQL bir bildirim dilidir ve istediklerimizi yapmak zorunda değiliz).

Bununla birlikte, sorgudaki bir bileşik anahtarın sütunları için aynı sıralamada bulunmaya bayılıyorum, ancak bazen ORM veya ActiveRecord kullandığımız zaman, kaçınılmazdır, yii2 gibi bazı çerçevelerde, ilişki ölçütlerini özelleştirmek, ilişkinin sonuna eklenecektir. "açık" bir koşul olmakla birlikte, bir uygulamanın farklı bölümlerinde QueryBuilders'in özelliklerine hala ihtiyacımız var.


-2

BİR WHERE / SAHİP maddeleri olarak kullanılan ve yüksek seçicilik vardır alanı (benzersiz değerlerin sayısını / kayıtların toplam sayısı>% 10 ~ 20%) MUST dizine.

Bu nedenle, ASI_EVENT_TIMEsütununuzun birçok olası değeri varsa, önce hepsini dizinleyin. Sonra @ypercube’in söylediği gibi, onları yeniden düzenlemeyi deneyin ve EXPLAIN'in size ne söylediğini görün. Her yerde aynı olmalı.

Ek olarak, SQL LIKE Filtrelerini İndekslemeye göz atmanızı istiyorum . Cevabınız gereken şey olmasa da, başlık altında endekslemenin nasıl çalıştığını öğreneceksiniz.

* Düzenleme: Dizin oluşturma hakkında daha fazla bilgi için yorumlarda aşağıda verilen bağlantılara bakın.


8
-1 Her sütunun indekslenmesi en iyi yöntem değildir. Her endeks size birçok yolla mal olur. Genellikle seçicilik ve sıklık sırasına göre, genellikle birden çok sütundan oluşan iyi dizinleri seçtiğinizden emin olun. Bu, SQL Server eğimli olabilir, ancak dizin bilgisi hala geçerlidir: sqlskills.com/BLOGS/KIMBERLY/post/… .
Eric Humphrey - saat

@Eric Humphrey +1 Açıklama ve Kimberly'nin sitesine bağlantı için.
Matt M

yanılıyorsunuz, sütun üzerinde dizine sahip olmak bazen belirli sorgularda performansınıza zarar verebilir: mysqlperformanceblog.com/2007/08/28/… . ASLA kural kuralını kullanmamalısınız: bazen işe yarar, bazen işe yaramaz.
sumar

Tamam, katılıyorum. Ancak, değer seçiciliğinin düşük olması durumunda bu geçerlidir. Patrick'in (bu soru yazarı) DATETIME olan kullandığı veri türünü dikkate alarak indeksleme yapılması önerilir. Genellikle, bu tür alanların, yalnızca birkaç olası tarih kullandığında tuhaf bir durum olmadığı sürece, oldukça büyük bir değerler kümesi vardır. * Daha net ve geçerli bir ifade vermek için yukarıdaki cevabımı düzenleyeceğim.
Eye
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.