2011-11-21 18 views
11

katılmak, ama hala neden açıklayamam katılmak sol mySQL sorgu 115 ms Vs 478ms. Her ikisi de InnoDB kullanıyorlar ve tanımlanmış ilişkiler var. 'Card_legality' yaklaşık 200k satır içerir, 'legality' tablosu ise 11 satır içerir.Neden, 'önemli ölçüde' içimdeki daha hızlı Bunu araştırdık

CREATE TABLE `card_legality` (
    `card_id` varchar(8) NOT NULL DEFAULT '', 
    `legality_id` int(3) NOT NULL, 
    `cl_boolean` tinyint(1) NOT NULL, 
    PRIMARY KEY (`card_id`,`legality_id`), 
    KEY `legality_id` (`legality_id`), 
    CONSTRAINT `card_legality_ibfk_2` FOREIGN KEY (`legality_id`) REFERENCES `legality` (`legality_id`), 
    CONSTRAINT `card_legality_ibfk_1` FOREIGN KEY (`card_id`) REFERENCES `card` (`card_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

Ve: İşte her biri için yapıdır

CREATE TABLE `legality` (
    `legality_id` int(3) NOT NULL AUTO_INCREMENT, 
    `l_name` varchar(16) NOT NULL DEFAULT '', 
    PRIMARY KEY (`legality_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=latin1; 

Ben sadece SOL-JOIN kullanabilirsiniz, ancak bu, çok doğru ... herhangi bir düşünce lütfen görünmüyor?

GÜNCELLEME: İstendiği gibi, her biri için açıklamanın sonuçlarını ekledim. Daha önce çalıştırılmış, ama bundan tam bir anlayış var taklit yok ..

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE cl ALL PRIMARY NULL NULL NULL 199747 Using where 
1 SIMPLE l eq_ref PRIMARY PRIMARY 4 hexproof.co.uk.cl.legality_id 1 

VE, iç birleşim:

id select_type table type possible_keys key key_len   ref       rows Extra 
1 SIMPLE l ALL PRIMARY NULL NULL NULL 11 
1 SIMPLE cl ref PRIMARY,legality_id legality_id 4 hexproof.co.uk.l.legality_id 33799 Using where 
+0

Bu arada 'card_id' bir seçimim olmadığı için VARCHAR'tır, normalde bunu kabul etmem. – Ben

cevap

9

Bu kart_id üzerindeki varchar nedeniyle. MySQL, card_id'deki indeksi burada belirtildiği şekilde card_id olarak kullanamaz. mysql type conversion. önemli bir parçası bir numara ile bir dize sütunun karşılaştırmaları için

olduğunu MySQL hızla değer arayan sütun üzerinde bir endeksi kullanamazsınız. str_col bir endeksli dizesi sütunu ise şu açıklamada arama yaparken, dizin kullanılamaz:

SEÇ * tbl_name WHERE str_col = 1; Bunun nedeni, 'un '1', '1' veya '1a' gibi 1 değerine dönüştürülebilen birçok farklı dizenin bulunmasıdır.Eğer

SELECT cl.`cl_boolean`, l.`l_name` 
FROM `card_legality` cl 
INNER JOIN `legality` l ON l.`legality_id` = cl.`legality_id` 
WHERE cl.`card_id` = '23155' 

ve

SELECT cl.`cl_boolean`, l.`l_name` 
FROM `card_legality` cl 
LEFT JOIN `legality` l ON l.`legality_id` = cl.`legality_id` 
WHERE cl.`card_id` = '23155' 

için sorguları değiştirirseniz

Sen hızında büyük bir iyileşme göreceksiniz ve ayrıca farklı İZAH görmelisiniz. Orada Using where; Using index ve ikinci Using index olduğunu

> desc id_test; 
+-------+------------+------+-----+---------+-------+ 
| Field | Type  | Null | Key | Default | Extra | 
+-------+------------+------+-----+---------+-------+ 
| id | varchar(8) | NO | PRI | NULL |  | 
+-------+------------+------+-----+---------+-------+ 
1 row in set (0.17 sec) 

> select * from id_test; 
+----+ 
| id | 
+----+ 
| 1 | 
| 2 | 
| 3 | 
| 4 | 
| 5 | 
| 6 | 
| 7 | 
| 8 | 
| 9 | 
+----+ 
9 rows in set (0.00 sec) 

> explain select * from id_test where id = 1; 
+----+-------------+---------+-------+---------------+---------+---------+------+------+--------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra     | 
+----+-------------+---------+-------+---------------+---------+---------+------+------+--------------------------+ 
| 1 | SIMPLE  | id_test | index | PRIMARY  | PRIMARY | 10  | NULL | 9 | Using where; Using index | 
+----+-------------+---------+-------+---------------+---------+---------+------+------+--------------------------+ 
1 row in set (0.00 sec) 


> explain select * from id_test where id = '1'; 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra  | 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------------+ 
| 1 | SIMPLE  | id_test | const | PRIMARY  | PRIMARY | 10  | const | 1 | Using index | 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------------+ 
1 row in set (0.00 sec) 

İlk durumda: İşte

Bunu göstermek için de benzer (ama daha kolay) testidir. Ayrıca ref, NULL veya CONST'dur. Söylemeye gerek yok, ikincisi daha iyidir.

+0

aha! Parlak! 'Card_id' bir INT olarak arama yaparken, doğru bir VARCHAR olsaydı, bu sorguları olması gerekenden 600 kat daha yavaş hale getirdi! Teşekkür ederim Andreas :) – Ben

+0

Evet. Çok iyi bilgi burada teşekkürler Andreas. – stefgosselin

+0

Bunun açıklandığı bir bağlantı ekledim. İyi bir okuma. –

3

O sorguları hem EXPLAIN çalışacaktı. Sadece SELECT her EXPLAIN ile öneki ve bunları çalıştırın. MySQL'in optimizasyonu ve sorguları nasıl yürüttüğü hakkında gerçekten faydalı bilgiler verir.

+3

Hazır konuya dayanarak, OP'nin "EXPLAIN" i nasıl kullanacağının farkında olmasının oldukça büyük bir şansı olduğunu söyleyebilirim. Her ne şekilde olursa olsun, bu tür bir bilgi, bir soruna cevap olarak verilmelidir. – Naatan

+0

Merhaba L2G, yorumunuz için teşekkürler. ** EXPLAIN ** fonksiyonuna devam edip ne bulabileceğimi göreceğim. Mysql kılavuzu biraz eksik (ya da en azından bana). Çok teşekkürler – Ben

0

MySql'in Left Joins için daha iyi bir optimizasyona sahip olduğundan eminim - şu anda bunu destekleyen bir kanıt yok.

ETA: Hızlı bir keşif turu ve ben görüşümü desteklemek için somut bir şey bulamıyorum ..... ben çünkü varchar olabilir şüpheli rağmen

+0

Teşekkürler K.Bob, benzer okudum ama kendiniz gibi; kanıt bulunamadı. – Ben

2

L2G, bunu hemen hemen özetlenebilir vardır card_id için kullanılan tür.

Benchmarking/profil quickies için this informative page yazdırdım. Burada hızlı bir fakir-mans profilleme tekniğidir:

Time a SQL on MySQL 
Enable Profiling 
mysql> SET PROFILING = 1 
... 
RUN your SQLs 
... 
mysql> SHOW PROFILES; 

+----------+------------+-----------------------+ 
| Query_ID | Duration | Query     | 
+----------+------------+-----------------------+ 
|  1 | 0.00014600 | SELECT DATABASE()  | 
|  2 | 0.00024250 | select user from user | 
+----------+------------+-----------------------+ 
mysql> SHOW PROFILE for QUERY 2; 

+--------------------------------+----------+ 
| Status       | Duration | 
+--------------------------------+----------+ 
| starting      | 0.000034 | 
| checking query cache for query | 0.000033 | 
| checking permissions   | 0.000006 | 
| Opening tables     | 0.000011 | 
| init       | 0.000013 | 
| optimizing      | 0.000004 | 
| executing      | 0.000011 | 
| end       | 0.000004 | 
| query end      | 0.000002 | 
| freeing items     | 0.000026 | 
| logging slow query    | 0.000002 | 
| cleaning up     | 0.000003 | 
+--------------------------------+----------+ 

İyi-şanslar, ah ve bulgularını gönderin!

+0

Bu gerçekten yararlı bilgiler stefgosselin, teşekkürler. Prognozunuz aslında doğruydu, ama Andreas'ın açıklaması bunu açıkladı. Yardımınız için teşekkürler :) – Ben

İlgili konular