Bileşik anahtarın ilk kısmı olarak DATETIME olan birincil anahtar dizini hiçbir zaman kullanılmaz


17

PRİMER ANAHTARIN ilk parçası olarak bir DATETIME (hatta bir tarih) INDEXING ile ilgili bir sorun var.

MySQL 5.5 kullanıyorum

İşte benim iki tablo:

-- This is my standard table with dateDim as a dateTime

CREATE TABLE `stats` (
 `dateDim` datetime NOT NULL,
 `accountDim` mediumint(8) unsigned NOT NULL,
 `execCodeDim` smallint(5) unsigned NOT NULL,
 `operationTypeDim` tinyint(3) unsigned NOT NULL,
 `junkDim` tinyint(3) unsigned NOT NULL,
 `ipCountryDim` smallint(5) unsigned NOT NULL,
 `count` int(10) unsigned NOT NULL,
 `amount` bigint(20) NOT NULL,
 PRIMARY KEY (`dateDim`,`accountDim`,`execCodeDim`,`operationTypeDim`,`junkDim`,`ipCountryDim`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8


-- Here is a copy with datDim as an integer

CREATE TABLE `stats_todays` (
`dateDim` int(11) unsigned NOT NULL,
 `accountDim` mediumint(8) unsigned NOT NULL,
 `execCodeDim` smallint(5) unsigned NOT NULL,
 `operationTypeDim` tinyint(3) unsigned NOT NULL,
 `junkDim` tinyint(3) unsigned NOT NULL,
 `ipCountryDim` smallint(5) unsigned NOT NULL,
 `count` int(10) unsigned NOT NULL,
 `amount` bigint(20) NOT NULL,
 PRIMARY KEY (`dateDim`,`accountDim`,`execCodeDim`,`operationTypeDim`,`junkDim`,`ipCountryDim`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Her iki tabloyu da aynı verilerle dolduruyorum (10.000 000 civarında)

Fakat:

  • istatistik tablosunda dateDim için DATETIME kullanın
  • stats_todays, dateDim için TO_DAYS () ile un INTEGER kullan

Benim sorum: MySQL neden dizinin ilk bölümü bir datetime olduğunda PRIMARY KEY KULLANMAYIN ??? Çok garip çünkü aynı verilerle ancak INTEGER ve TO_DAYS (dateDim) ile aynı istek sallanır ....

İstatistikler tablosu (ve datetime) ile örnek:

SELECT * 
FROM `stats`  
WHERE 
   dateDim = '2014-04-03 00:00:00' 
   AND accountDim = 4
   AND execCodeDim = 9
   AND operationTypeDim = 1
   AND junkDim = 5
   AND ipCountryDim = 3

=> 1 result (4.5sec)

Explain:

id  select_type     table   type    possible_keys   key     key_len     ref     rows           Extra
1   SIMPLE          stats   ALL           NULL     NULL       NULL      NULL    8832329     Using where

Diğer tablo istatistiklerinde bugünkü istek (INTEGER ve TO_DAYS () ile)

EXPLAIN SELECT * 
FROM `stats_todays`  
WHERE 
   dateDim = TO_DAYS('2014-04-03 00:00:00')
   AND accountDim = 4
   AND execCodeDim = 9
   AND operationTypeDim = 1
   AND junkDim = 5
   AND ipCountryDim = 3

=> Result 1 row (0.0003 sec) 

Explain:

id  select_type     table          type     possible_keys   key     key_len     ref                               rows  Extra
1   SIMPLE         stats_todays     const   PRIMARY     PRIMARY     13  const,const,const,const,const,const     1    

Tam yazıyı okursanız, istek bir INTEGER dateDim alanı ile tam olarak aynı kardinalite ile çalıştığından, bunun düşük bir kardinalite sorunu olmadığını anlarsınız ...

İşte bazı gelişmiş ayrıntılar:

SELECT COUNT( DISTINCT dateDim )
FROM stats_todays
UNION ALL
SELECT COUNT( DISTINCT dateDim )
FROM stats;

Result:


COUNT(DISTINCT dateDim)
2192
2192

INDEX açıklaması:

SHOW INDEXES FROM `stats` 

Table   Non_unique  Key_name    Seq_in_index    Column_name     Collation   Cardinality     Sub_part    Packed  Null    Index_type  Comment     Index_comment
stats   0            PRIMARY          1         dateDim           A     6921           NULL                 NULL        BTREE        
stats   0            PRIMARY          2         accountDim        A     883232         NULL                 NULL        BTREE        
stats   0            PRIMARY          3         execCodeDim       A     8832329     NULL                NULL        BTREE        
stats   0            PRIMARY          4         operationTypeDim  A     8832329     NULL                NULL        BTREE        
stats   0            PRIMARY          5         junkDim           A     8832329     NULL                NULL        BTREE        
stats   0            PRIMARY          6         ipCountryDim      A     8832329     NULL                NULL        BTREE       

SHOW INDEXES FROM `stats_todays` 

Table   Non_unique  Key_name    Seq_in_index    Column_name     Collation   Cardinality     Sub_part    Packed  Null    Index_type  Comment     Index_comment
stats_todays    0   PRIMARY     1              dateDim              A        7518   NULL                   NULL         BTREE        
stats_todays    0   PRIMARY     2              accountDim           A        4022582    NULL                   NULL         BTREE        
stats_todays    0   PRIMARY     3              execCodeDim          A        8045164    NULL                   NULL         BTREE        
stats_todays    0   PRIMARY     4              operationTypeDim     A        8045164    NULL                   NULL         BTREE        
stats_todays    0   PRIMARY     5              junkDim              A        8045164    NULL                   NULL         BTREE        
stats_todays    0   PRIMARY     6              ipCountryDim         A        8045164    NULL                   NULL         BTREE        

SELECT dateDim, COUNT (*) İSTANBULDAN GRUPLA Tarihe göre

  • 2192 farklı tarih olduğunu ve bölümün pürüzsüz olduğunu söyler (tarihe göre yaklaşık 3000 - 4000 satır)
  • tabloda 8 831 990 satır var
  • Diğer tablo için aynı
  • COVERING INDEX ile denedim (* tüm PK sütunları ile değiştirerek) => hiçbir şey değişmedi
  • Force | use index => hiçbir şey değişmedi denedim
  • Tarih alanı yerine tarih saatiyle aynı
  • Birincil anahtar yerine INDEX veya UNIQUE ile aynı

Bu gerçekten garip. dateBunun yerine kullanırsanız da aynı şey olur datetimemu?
ypercubeᵀᴹ

evet aynı şeyi yapıyor

1
Ve eğer kaçarsan WHERE dateDim = DATE('2014-04-03 00:00:00')?
ypercubeᵀᴹ

1
Pk'nin yeniden siparişi ile çalışır. Ama gerçekte, nerede yan tümcesinde sadece dateDim ve accountDim ile istekte bulunmak istiyorum. Vaka çalışması için tüm pk alanlarını kullanıyorum ...

1
NEREDE dateDim = DATE ('2014-04-03 00:00:00') => hiçbir şey değişmedi

Yanıtlar:


6

Bu 5.5.x sürümünde bir hata. Buraya bakın

Bu, sorgunuzun

SELECT * 
FROM `stats`  
WHERE 
   dateDim = CAST('2014-04-03 00:00:00' as datetime)
   AND accountDim = 4
   AND execCodeDim = 9
   AND operationTypeDim = 1
   AND junkDim = 5
   AND ipCountryDim = 3

1

Tablonun int sürümünden beri

CREATE TABLE `stats_todays` ( 
`dateDim` int(11) unsigned NOT NULL, 
 `accountDim` mediumint(8) unsigned NOT NULL, 
 `execCodeDim` smallint(5) unsigned NOT NULL, 
 `operationTypeDim` tinyint(3) unsigned NOT NULL, 
 `junkDim` tinyint(3) unsigned NOT NULL, 
 `ipCountryDim` smallint(5) unsigned NOT NULL, 
 `count` int(10) unsigned NOT NULL, 
 `amount` bigint(20) NOT NULL, 
 PRIMARY KEY (`dateDim`,`accountDim`,`execCodeDim`,`operationTypeDim`,`junkDim`,`ipCountryDim`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 

sorgu açısından iyi çalışır, dateDim datetime dizesinin UNIX_TIMESTAMP () içermelidir . Sorgunuz şu şekilde görünecektir:

SELECT *        
FROM `stats`         
WHERE        
   dateDim = UNIX_TIMESTAMP('2014-04-03 00:00:00')
   AND accountDim = 4       
   AND execCodeDim = 9       
   AND operationTypeDim = 1       
   AND junkDim = 5       
   AND ipCountryDim = 3       
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.