2016-04-04 24 views
2

Bu benim tablolar: tarih colum ve test_log indekslendiyseoptimize MySQL sorgu

SELECT d.date, COUNT(l.id) 
FROM test_dates d 
LEFT JOIN test_log l ON l.timest>=d.date AND l.timest<d.date + INTERVAL 1 DAY 
GROUP BY d.date 

tablo test_dates:

CREATE TABLE IF NOT EXISTS `test_dates` (
    `date` date NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

CREATE TABLE IF NOT EXISTS `test_log` (
    `id` int(10) unsigned NOT NULL, 
    `timest` datetime NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

ALTER TABLE `test_dates` 
    ADD PRIMARY KEY (`date`); 

ALTER TABLE `test_log` 
    ADD PRIMARY KEY (`id`), 
    ADD KEY `emissione` (`timest`); 

Bugüne başına günlükleri saymak için bu sorgu var tablo zaman sütununda endekslenir.

Ancak bu sorguyu açıklarken "ALL" ve NULL anahtarını sorguladım.

+-----+--------------+--------+-------------+--------+----------------+----------+----------+------+--------+-----------+------------------------------------------------+--+ 
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered |      Extra      | | 
+-----+--------------+--------+-------------+--------+----------------+----------+----------+------+--------+-----------+------------------------------------------------+--+ 
| 1 | SIMPLE  | d  | NULL  | index | PRIMARY  | PRIMARY | 3  | NULL | 705 | 100.00 | Using index         | | 
| 1 | SIMPLE  | l  | NULL  | ALL | emissione  | NULL  | NULL  | NULL | 98256 | 100.00 | Range checked for each record (index map: 0x2) | | 
+-----+--------------+--------+-------------+--------+----------------+----------+----------+------+--------+-----------+------------------------------------------------+--+ 

Neden mysql tablo dizinlerini kullanamaz?

Günlük tabloları yaklaşık 100000 satır var ve sorgu çok yavaş.

+0

Muhtemelen sorgu yavaş? Minimum olarak, sorgu performansıyla ilgili sorular, tüm ilgili tablolar için CREATE ifadelerini (ve tercihen örnek verileri de) ve EXPLAIN sonucunu gerektirir. – Strawberry

+0

Tamam, güncellemeyi yapıyorum. – Tobia

cevap

2

bir korelasyon alt sorgu olarak bu çalıştırmayı deneyin: GROUP BY indeksler kullanırken

SELECT d.date, 
     (SELECT COUNT(l.id) 
     FROM log l 
     WHERE l.timest >= d.date AND l.timest < d.date + INTERVAL 1 DAY 
     ) as cnt 
FROM dates d; 

MySQL çok iyi değil. Bazen bir alt sorgunun kullanılması performansa önemli bir artış sağlayabilir. Masanızın doğru dizinleri var.

+0

Deniyorum ama önemli bir performans artışım yok ... – Tobia

+0

İş yerinde test (MySQL 5.6.26): fark yok. Evde test (MariaDB 10.0.19): Büyük fark. Belki de MySQL 5.7, MariaDB 10 kadar iyidir. –

+0

Bunu mysql 5.6.26 ile test ettiğimi onaylıyorum. – Tobia

0

Dizin ve ilişkili alt sorgu sizin için çalışmıyorsa, daha iyi seçeneğiniz tarih tablonuzu güncellemek ve bir özet sayısı sütunu eklemek olabilir. Daha sonra, günlük tablonuza bir ekleme yaptığınızda, söz konusu tarih için tarih tablosunda sayacınıza 1 ekleyin. Henüz böyle bir kayıt yoksa, yeni bir kayıt olduğundan bir tane ekleyin ve sayısını 1'e ayarlayın.

Ardından, yapmanız gereken tek şey tarih aralığına göre tarih tablonuzdan bir sum() seçin ve ayrıntılara asla bakmayın. Muhtemel gözden geçirme için belirli bir tarih seçildiğinde, temel verileri sorgulayabilirsiniz.

0

Çevreyi çevirin. İlk (aşağıda, alt sorgu bakınız) ikinci masada verimli GROUP BY yapın sonra eksik günlerde (dış sorgu) doldurun: tarih aralığını sınırlamak isterseniz

SELECT date, 
     IFNULL(log.ct, 0) AS ct 
    FROM 
     (SELECT DATE(timest) AS date, 
       COUNT(*) AS ct 
      FROM test_log 
      GROUP BY date 
    ) AS log 
    RIGHT JOIN test_dates AS d USING(date); 

, bir WHERE maddesini eklemek hem alt sorgu ve dış sorgu.