MySQL

2013-06-13 14 views
8

'daki iç birleştirme tablosundaki dizini kullanma 200 milyon kayıtlı Masa Foo'm ve 1000 kayıtlı Table Bar'ım var, bunlar bire-bire bağlı. Foo.someTime ve Bar.someField sütunları için dizinler vardır.MySQL

mysql> select * from Foo f inner join Bar b on f.table_id = b.table_id where f.someTime  between '2008-08-14' and '2018-08-14' and b.someField = 1 limit 20; 
... 
20 rows in set (0.00 sec) 

(2) Bu sadece sonsuza kadar sürer (tek değişiklik b: Ayrıca Bar'da 900 kayıt 100 (1) Bu sorgu hemen yürütür 2.

ait someField var, 1 someField var. someField = 2):

mysql> select * from Foo f inner join Bar b on f.table_id = b.table_id where f.someTime  between '2008-08-14' and '2018-08-14' and b.someField = 2 limit 20; 

(3) Fakat bırakma durumunda bir ara ile maddesi de hemen işleme göre burada:

mysql> select * from Foo f inner join Bar b on f.table_id = b.table_id where b.someField = 2 limit 20; 
... 
20 rows in set (0.00 sec) 

(4) Ayrıca ben index kullanımı zorlayarak onu hızlandırabilir: Burada

mysql> select * from Foo f inner join Bar b force index(someField) on f.table_id = b.table_id where f.someTime  between '2008-08-14' and '2018-08-14' and b.someField = 2 limit 20; 
... 
20 rows in set (0.00 sec) 

üzerinde açıklamak sorguyu açıklamak (2) (sonsuza kadar sürer olan) İşte

+----+-------------+-------+--------+-------------------------------+-----------+---------+--------------------------+----------+-------------+ 
| id | select_type | table | type | possible_keys     | key  | key_len | ref      | rows  | Extra  | 
+----+-------------+-------+--------+-------------------------------+-----------+---------+--------------------------+----------+-------------+ 
| 1 | SIMPLE  | g  | range | bar_id,bar_id_2,someTime  | someTime | 4  | NULL      | 95022220 | Using where | 
| 1 | SIMPLE  | t  | eq_ref | PRIMARY,someField,bar_id  | PRIMARY | 4  | db.f.bar_id    |  1 | Using where | 
+----+-------------+-------+--------+-------------------------------+-----------+---------+--------------------------+----------+-------------+ 

olduğu (4) (ki bu kuvvet endeksine sahiptir)

+----+-------------+-------+------+-------------------------------+-----------+---------+--------------------------+----------+-------------+ 
| id | select_type | table | type | possible_keys     | key  | key_len | ref      | rows  | Extra  | 
+----+-------------+-------+------+-------------------------------+-----------+---------+--------------------------+----------+-------------+ 
| 1 | SIMPLE  | t  | ref | someField      | someField | 1  | const     |  92 |    | 
| 1 | SIMPLE  | g  | ref | bar_id,bar_id_2,someTime  | bar_id | 4  | db.f.foo_id    | 10558024 | Using where | 
+----+-------------+-------+------+-------------------------------+-----------+---------+--------------------------+----------+-------------+ 

Bu yüzden soru, MySQL'in doğru indeksi kullanmasını nasıl öğretecek? Sorgu ORM tarafından oluşturulur ve yalnızca bu iki alanla sınırlı değildir. Ve ayrıca sorguyu değiştirmekten kaçınmak güzel olurdu (yine de iç birleştirmenin buraya uyduğundan emin değilim).

UPDATE: bu sorgu (2) 0.00 saniyede çalıştırdıktan sonra

mysql> create index index_name on Foo (bar_id, someTime); 

.

+5

Lütfen SELECT'inizin herhangi bir birleşimi varsa ** asla 'SELECT *' yapmayın. Bunun yerine, hangi yıldızı kastettiğinizi belirtin. Örneğin, 'SELECT f. * FROM foo f JOIN bar b ...' tamam. Aksi halde, hangi alanların * * 'getirdiğini ve daha yavaş – mvp

+0

yapacağı anlamına gelmez. * SELECT *' i sadece örnek olarak gerçek DB ORM'de sorguyu * oluşturmadan üretir. –

cevap

4

foo(table_id, sometime) için bileşik dizin oluşturursanız, çok yardımcı olur. Bunun nedeni sunucu ilk önce table_id ve ardından sometime tarafından ayarlanan sonuçları daraltabilecektir.

LIMIT kullanıldığında, sunucunun WHERE kısıtlamanız için yeterli olması durumunda hangi satırların getirileceğini garanti etmediğini unutmayın. Teknik olarak, her uygulama size biraz farklı sonuç verebilir. Belirsizlikten kaçınmak istiyorsanız, LIMIT'u kullandığınızda her zaman ORDER BY'u kullanmalısınız. Ancak, bu aynı zamanda uygun indeksler oluştururken daha dikkatli olmanız gerektiği anlamına gelir.

+0

Şu anda Foo'da 6 sütun ve Bar'da 3 sütun var, bu da olası kombinasyonlarda 'nereye 'dahil edilebiliyor. Şu anki indeksleri 'foo (alan1)', 'foo (field2)' vb. Çıkarmalı ve bunları foo (bar_id, field1) 'vb. Ile değiştirmeli miyim? –

+0

Bileşik indeksi '(a, b)' 'a 've' (a, b)' (her ikisi de 'a' ve' b' biliniyorsa) 'ları aramak için iyidir, fakat 'b''de değil - '(b)' üzerinde dizin oluşturulmasını gerektirir. Eğer (a, b) 'zaten varsa,' (b, a) 'dizinine gerek yoktur. Ayrıca, belirli bir sırayla '(a, b)' yi kullanmalısınız - önce en seçici sütun. – mvp

+0

Çözümünüz bir çekicilik gibi çalışır, çok teşekkürler. –