2016-09-02 24 views
5

Tôi có một truy vấn mất 10-20 giây, nhưng tôi chắc chắn nó có thể được tối ưu hóa, tôi chỉ không đủ tốt để làm điều đó. Tôi muốn một số trợ giúp và giải thích để tôi có thể áp dụng nó cho các truy vấn tương tự. Đây là câu hỏi của tôi:tối ưu hóa truy vấn mysql với 2 tham gia và nhóm theo mệnh đề

SELECT 
     `store_formats`.`Store Nbr`, 
     `store_formats`.`Store Name`, 
     `store_formats`.`Format Name`, 
     `eds_sales`.`Date`, 
     sum(`eds_sales`.`EPOS Sales`) AS Sales, 
     sum(`eds_sales`.`EPOS Quantity`) AS Quantity 
     FROM 
     `eds_sales` 
     INNER JOIN `item_codes` ON `eds_sales`.`Prime Item Nbr` = `item_codes`.`Customer Item` 
     INNER JOIN `store_formats` ON `eds_sales`.`Store Nbr` = `store_formats`.`Store Nbr` 
     WHERE 
     `eds_sales`.`Store Nbr` IN ($storenbr) AND 
     `eds_sales`.`Date` BETWEEN '$startdate' AND '$enddate' AND 
     `eds_sales`.`Client` = '$customer' AND 
     `eds_sales`.`Retailer` IN ($retailer) AND 
     `store_formats`.`Format Name` IN ($storeformat) AND 
     `item_codes`.`Item Number` IN ($products) 
     GROUP BY 
     `store_formats`.`Store Name`, 
     `store_formats`.`Store Nbr`, 
     `store_formats`.`Format Name`, 
     `eds_sales`.`Date` 

Đây là kết quả giải thích: enter image description here

Như bạn sẽ thấy ở đó, tôi đã cố gắng và tạo ra một vài chỉ số với các cột có liên quan với không nhiều thành công. Sự chậm trễ chính là do việc sao chép sang bảng tạm thời mà tôi nghĩ.

Đó là những bảng tham gia:

store_formats:

CREATE TABLE `store_formats` (
`id` int(12) NOT NULL, 
`Store Nbr` smallint(5) UNSIGNED DEFAULT NULL, 
`Store Name` varchar(27) DEFAULT NULL, 
`City` varchar(19) DEFAULT NULL, 
`Post Code` varchar(9) DEFAULT NULL, 
`Region #` int(2) DEFAULT NULL, 
`Region Name` varchar(10) DEFAULT NULL, 
`Distr #` int(3) DEFAULT NULL, 
`Dist Name` varchar(26) DEFAULT NULL, 
`Square Footage` varchar(7) DEFAULT NULL, 
`Format` int(1) DEFAULT NULL, 
`Format Name` varchar(23) DEFAULT NULL, 
`Store Type` varchar(20) DEFAULT NULL, 
`TV Region` varchar(12) DEFAULT NULL, 
`Pharmacy` varchar(3) DEFAULT NULL, 
`Optician` varchar(3) DEFAULT NULL, 
`Home Shopping` varchar(3) DEFAULT NULL, 
`Retailer` varchar(15) DEFAULT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
ALTER TABLE `store_formats` 
ADD PRIMARY KEY (`id`), 
ADD UNIQUE KEY `uniqness` (`Store Nbr`,`Store Name`,`Format`), 
ADD KEY `Store Nbr_2` (`Store Nbr`,`Format Name`,`Store Name`); 

eds_sales:

CREATE TABLE `eds_sales` (
`id` int(12) UNSIGNED NOT NULL, 
`Prime Item Nbr` mediumint(7) NOT NULL, 
`Prime Item Desc` varchar(255) NOT NULL, 
`Prime Size Desc` varchar(255) NOT NULL, 
`Variety` varchar(255) NOT NULL, 
`WHPK Qty` int(5) NOT NULL, 
`SUPPK Qty` int(5) NOT NULL, 
`Depot Nbr` int(5) NOT NULL, 
`Depot Name` varchar(50) NOT NULL, 
`Store Nbr` smallint(5) UNSIGNED NOT NULL, 
`Store Name` varchar(255) NOT NULL, 
`EPOS Quantity` smallint(3) NOT NULL, 
`EPOS Sales` decimal(13,2) NOT NULL, 
`Date` date NOT NULL, 
`Client` varchar(10) NOT NULL, 
`Retailer` varchar(50) NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 
ALTER TABLE `eds_sales` 
ADD UNIQUE KEY `uniqness` (`Prime Item Nbr`,`Prime Item Desc`,`Prime Size Desc`,`Variety`,`WHPK Qty`,`SUPPK Qty`,`Depot Nbr`,`Depot Name`,`Store Nbr`,`Store Name`,`Date`,`Client`) USING BTREE, 
ADD KEY `Store Nbr` (`Store Nbr`), 
ADD KEY `Prime Item Nbr_2` (`Prime Item Nbr`,`Date`), 
ADD KEY `id` (`id`) USING BTREE, 
ADD KEY `Store Nbr_2` (`Prime Item Nbr`,`Store Nbr`,`Date`,`Client`,`Retailer`) USING BTREE, 
ADD KEY `Client` (`Client`,`Store Nbr`,`Date`), 
ADD KEY `Date` (`Date`,`Client`,`Retailer`); 

item_codes:

CREATE TABLE `item_codes` (
`id` int(12) NOT NULL, 
`Item Number` varchar(30) CHARACTER SET latin1 NOT NULL, 
`Customer Item` mediumint(7) NOT NULL, 
`Description` varchar(255) CHARACTER SET latin1 NOT NULL, 
`Status` varchar(15) CHARACTER SET latin1 NOT NULL, 
`Customer` varchar(30) CHARACTER SET latin1 NOT NULL, 
`Sort Name` varchar(255) CHARACTER SET latin1 NOT NULL, 
`EquidataCustomer` varchar(30) CHARACTER SET latin1 NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
ALTER TABLE `item_codes` 
ADD PRIMARY KEY (`id`), 
ADD UNIQUE KEY `uniq` (`Item Number`,`Customer Item`,`Customer`,`EquidataCustomer`), 
ADD KEY `Item Number_2` (`Item Number`,`Sort Name`,`EquidataCustomer`), 
ADD KEY `Customer Item` (`Customer Item`,`Item Number`,`Sort Name`,`EquidataCustomer`), 
ADD KEY `Customer Item_2` (`Customer Item`,`Item Number`,`EquidataCustomer`); 

Vì vậy, câu hỏi của tôi: Như bạn có thể thấy tôi đang tham gia 3 bảng và tôi đang tìm kiếm doanh số theo ngày theo định dạng cửa hàng. Tôi đã thử các loại tham gia khác nhau, hoặc ví dụ thay vì tham gia bán hàng cho item_codes và store_formats, tham gia store_formats cho những người khác, nhưng với cùng một kết quả. Tôi cũng đi qua một số mảng của các biến bằng cách sử dụng IN như những cái được cho ăn bởi các hộp chọn trong ứng dụng.

  1. Cách tốt nhất để tham gia những bảng
  2. Đề nghị các chỉ số tốt nhất cho mỗi bảng
  3. tại sao tôi nhận được bảng tạm thời? có phải vì nhóm đó không? có cách giải quyết nào không?
  4. Nếu cần có bảng tạm thời để tăng tốc độ sáng tạo này? (Tôi đã có thư mục dữ liệu trong một cuộc đột kích với 8 đĩa nhưng vẫn chậm
  5. Tất nhiên bất kỳ lựa chọn thay thế đề nghị được hoan nghênh

UPDATE:. Cập nhật bảng của tôi với một số gợi ý từ các ý kiến ​​

UPDATE: Modified my.cnf của tôi như hiệu suất tăng dưới (RAM của tôi là 8GB, 2 lõi,/data/tmp trên một cuộc đột kích 8 ổ đĩa, giống như nơi dữ liệu được)

tmpdir   = /dev/shm/:/data/tmp:/tmp 
lc-messages-dir = /usr/share/mysql 
skip-external-locking 
expire_logs_days  = 10 
max_binlog_size = 100M 
innodb_buffer_pool_size = 6G 
innodb_buffer_pool_instances = 6 
query_cache_type=1 
+1

Câu hỏi này có thể sẽ nhận được nhiều sự chú ý của chuyên gia hơn về [DBA exchange] (https://dba.stackexchange.com/). –

+0

Bạn có thể vui lòng [sửa] câu hỏi của mình để hiển thị tất cả các chỉ mục trên các bảng của bạn không? –

+0

thêm chỉ mục vào câu hỏi –

Trả lời

1

Selects chuyển thành các truy vấn để tôi tin rằng MySQL wo uld đã làm điều đó cho bạn rồi. Tôi sẽ kiểm tra kế hoạch thực hiện cho thông tin đó.

SELECT 
    stores.nbr, stores.name, stores.format, 
    epos.date, 
    sum(epos.sales) AS Sales, 
    sum(epos.qty) AS Quantity 
FROM 
    (SELECT `Date` as `date`, `EPOS Sales` as sales,`EPOS Quantity` as qty, `Prime Item Nbr` as item_number, `Store Nbr` as store_number 
FROM 
    `eds_sales` 
WHERE 
    `eds_sales`.`Store Nbr` IN ($storenbr) AND 
    `eds_sales`.`Date` BETWEEN '$startdate' AND '$enddate' AND 
    `eds_sales`.`Client` = '$customer' AND 
    `eds_sales`.`Retailer` IN ($retailer)) as epos 

    INNER JOIN 

    (SELECT `Customer Item` as custItem 
    FROM `item_codes` 
    WHERE 
    `item_codes`.`Item Number` IN ($products)) as items ON epos.item_number = items.custItem 

    INNER JOIN 

    (SELECT `Store Nbr` as nbr, `Store Name` as name, `Format Name` as format 
    FROM 
    `store_formats` 
    WHERE 
    `store_formats`.`Format Name` IN ($storeformat)) as stores ON epos.store_number = stores.nbr 
GROUP BY 
    stores.name, 
    stores.nbr, 
    stores.format, 
    epos.date 
+0

sửa đổi lớn, nhưng chính xác cùng hiệu suất –

2

(Quá nhiều để đưa vào một Nhận xét; xin vui lòng cho tôi xin lỗi cho việc sử dụng một câu trả lời.)

Khi bạn có INDEX(a)INDEX(a,b), cựu là không cần thiết và cần được loại bỏ. Tôi thấy khoảng 5 trường hợp như vậy.

Mỗi store_nbr có chính xác một store_name? Nếu có, thì dư thừa có store_name ở nhiều hơn một bảng.Tôi không biết ý định của store_formats, nhưng tôi đoán đó là một bảng để nhà store_name. Lưu ý rằng có một kích thước không phù hợp cho các kiểu dữ liệu của hai cột store_name và cho các cột store_nbr!

Có vẻ như mọi cửa hàng phải có một số duy nhất, nếu có, thì ADD UNIQUE KEY uniqness (Store Nbr, Store Name) có lẽ nên được chuyển thành PRIMARY KEY(store_nbr). (Xin lỗi, tôi sẽ không đặt dấu cách vào tên cột của bạn.)

Rất hiếm khi bắt đầu chỉ mục với ngày tháng, vì vậy hãy loại bỏ KEY Date_2 (Date, Client). Thay vào đó, hãy thêm INDEX(Client, store_nbr, Date); nên có tác động trực tiếp lên tốc độ truy vấn. Bạn có thể sẽ thấy sự thay đổi EXPLAIN SELECT....

int(4) - có lẽ bạn có nghĩa là SMALLINT UNSIGNED?

Date trong một số UNIQUE (hoặc PRIMARY) thường là "sai". 'Khách hàng' đã mua hai thứ giống nhau trong cùng một ngày?

Sau khi bạn đã thực hiện những thay đổi đó, hãy nói thêm một số điều khác.

Để thống nhất xem, vui lòng cung cấp SHOW CREATE TABLE.

Tránh cấu trúc này:

FROM (SELECT ...) 
JOIN (SELECT ...) ON ... 

Đó là không hiệu quả vì không subquery có một chỉ số để làm các JOIN hiệu quả.

+0

Xin chào, cảm ơn điểm đầu tiên, không chắc chắn cách hoạt động. Đối với các cột lặp lại, các cột đó đến từ các tệp excel, được nhập trực tiếp trong mysql. Tôi dự định loại bỏ chúng trong tương lai, nhưng bây giờ có một số sử dụng cho chúng trong một số truy vấn nhanh. Đối với uniqness, nếu tôi chuyển đổi khóa duy nhất này thành primary, nó sẽ vẫn là duy nhất? đã thay đổi chỉ mục bằng ngày tháng. loại dữ liệu được sửa đổi để khớp trên tất cả các bảng.cho ngày tháng duy nhất, nó cần phải giống như vậy, vì tôi không giao dịch với khách hàng, nhưng dữ liệu đến cho các cửa hàng, vì vậy uniqness được định nghĩa vào ngày-storenbr và những người khác –

+0

Tôi sẽ đăng chương trình của tôi tạo bảng và hiệu suất tommorow. thank you –

+0

Một 'PRIMARY KEY' là một khóa 'UNIQUE' là một' INDEX'. –

0

Move điều kiện trên bảng kết nối từ khoản WHERE đến tham gia của ON khoản:

SELECT 
`store_formats`.`Store Nbr`, 
`store_formats`.`Store Name`, 
`store_formats`.`Format Name`, 
`eds_sales`.`Date`, 
sum(`eds_sales`.`EPOS Sales`) AS Sales, 
sum(`eds_sales`.`EPOS Quantity`) AS Quantity 
FROM `eds_sales` 
JOIN `item_codes` 
    ON `eds_sales`.`Prime Item Nbr` = `item_codes`.`Customer Item` 
    AND `item_codes`.`Item Number` IN ($products) 
JOIN `store_formats` 
    ON `eds_sales`.`Store Nbr` = `store_formats`.`Store Nbr` 
    AND `store_formats`.`Format Name` IN ($storeformat) 
WHERE `eds_sales`.`Store Nbr` IN ($storenbr) 
AND `eds_sales`.`Date` BETWEEN '$startdate' AND '$enddate' 
AND `eds_sales`.`Client` = '$customer' 
AND `eds_sales`.`Retailer` IN ($retailer) 
GROUP BY 
`store_formats`.`Store Name`, 
`store_formats`.`Store Nbr`, 
`store_formats`.`Format Name`, 
`eds_sales`.`Date` 

Tạo các chỉ số sau:

CREATE INDEX IDX001 ON eds_sales (Client,`Store Nbr`,`Retailer`,`Date`); 
CREATE INDEX IDX002 ON store_formats (`Store Nbr`,`Format Name`); 

Nếu nó hoạt động, cho tôi biết và tôi sẽ giải thích tại sao.

Các vấn đề liên quan