Chỉ mục khóa chính với DATETIME là phần đầu tiên của khóa ghép không bao giờ được sử dụng


17

Tôi gặp vấn đề với việc CHỈ ĐỊNH MỘT ĐẠI SỐ (hoặc thậm chí là một ngày) là phần đầu tiên của KHÓA CHÍNH.

Tôi sử dụng MySQL 5.5

Đây là hai bảng của tôi:

-- 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

Tôi điền vào cả hai bảng với cùng một dữ liệu (gần 10 000 000)

Nhưng:

  • bảng thống kê sử dụng một dữ liệu dữ liệu cho dateDim
  • stats_todays sử dụng un INTEGER với TO_DAYS () cho dateDim

Câu hỏi của tôi là: tại sao MySQL không sử dụng KHÓA CHÍNH khi phần đầu tiên của chỉ mục là datetime ??? Điều này rất lạ vì Với cùng một dữ liệu nhưng được hợp nhất với một INTEGER và TO_DAYS (dateDim) cùng một yêu cầu đá ....

Ví dụ với bảng thống kê (và datetime):

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

Yêu cầu tương tự trên bảng stats_todays khác (Với INTEGER và TO_DAYS ())

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    

Nếu bạn đọc toàn bộ bài đăng, bạn hiểu rằng đó không phải là vấn đề về số lượng thẻ thấp vì yêu cầu hoạt động với cùng một số lượng chính xác với trường INTEGER dateDim ....

Dưới đây là một số chi tiết nâng cao:

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

Result:


COUNT(DISTINCT dateDim)
2192
2192

Dưới đây là mô tả INDEX:

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        

CHỌN dateDim, COUNT (*) TỪ thống kê NHÓM THEO dateDim VỚI ROLLUP

  • cho biết có 2192 ngày khác nhau và quá trình phân chia lại diễn ra suôn sẻ (khoảng 3000 - 4000 hàng theo ngày)
  • có 8 831 990 hàng trong bảng
  • Tương tự cho các bảng khác
  • Tôi đã thử với COVERING INDEX (thay thế * bằng tất cả các cột PK) => không có gì thay đổi
  • Tôi đã thử dùng lực | chỉ số => không có gì thay đổi
  • Tương tự với trường ngày thay vì datetime
  • Tương tự với INDEX hoặc UNIQUE thay vì khóa chính

Điều này thực sự kỳ lạ. Điều tương tự có xảy ra nếu bạn sử dụng datethay vì datetime?
ypercubeᵀᴹ

vâng, nó giống hệt nhau

1
Và nếu bạn chạy WHERE dateDim = DATE('2014-04-03 00:00:00')?
ypercubeᵀᴹ

1
Với một thứ tự của pk nó hoạt động. Nhưng trong thực tế, tôi muốn thực hiện một yêu cầu chỉ với dateDim và accountDim trong mệnh đề where. Tôi sử dụng tất cả các lĩnh vực pk cho nghiên cứu trường hợp ...

1
WHERE dateDim = DATE ('2014-04-03 00:00:00') => không có gì thay đổi

Câu trả lời:


6

Đây là một lỗi trong 5.5.x. Xem tại đây

Điều đó cho thấy rằng truy vấn của bạn nên

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

Kể từ phiên bản int của bảng

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 

hoạt động tốt về mặt truy vấn, bạn nên có dateDim chứa UNIX_TIMESTAMP () của chuỗi datetime. Bạn truy vấn sẽ trông giống như thế này:

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       
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.