Xử lý các bảng tạm thời khi tôi không kiểm soát các biến db


7

Tôi không có quyền kiểm soát đối với những thứ như tmp_table_sizemax_heap_table_size, vì vậy khi các bảng của chúng tôi tăng thời gian thực hiện bởi các truy vấn yêu cầu các bảng tạm thời đang tăng lên về mặt hình học.

Tôi tự hỏi liệu có cách nào để ngăn chặn MySQL sử dụng bảng tạm thời cho các truy vấn này không? Điều gì sẽ là cách tiếp cận tốt nhất trong tình huống này:

Dưới đây là một ví dụ về người phạm tội lớn nhất:

SELECT `skills`.`id`
FROM (`jobs_skills`)
JOIN `jobs` ON (`jobs`.`id` = `jobs_skills`.`job_id`)
JOIN `skills` ON (`skills`.`id` = `jobs_skills`.`skill_id`)
WHERE `jobs`.`job_visibility_id` = 1
AND `jobs`.`active` = 1
AND `skills`.`valid` = 1
AND `jobs_skills`.`skill_id` IN (96,101,103,108,121,2610,99,119,2607,102,104,112,113,122,1032,1488,2608,109,126,1438,2310,2318,2622,118,1046,1387,2609,100,116,123,2611,2612,2616,2618,114,127,1562,1587,1608,2276,2615,125,1070,1071,1161,1658,2613,2614,2617,105,110,111,120,1394,1435)
GROUP BY `jobs_skills`.`job_id`

trong đó copying to temp tablemất 107 giây, 99% tổng thời gian truy vấn.

Mặc dù lo ngại hội chứng tl; dr, tôi đang cung cấp. . .

CHI TIẾT THÊM

Đây là EXPLAINtuyên bố cho truy vấn:

+----+-------------+-------------+--------+----------------------+--------------+---------+----------------------------------+--------+----------------------------------------------+
| id | select_type | table       | type   | possible_keys        | key          | key_len | ref                              | rows   | Extra                                        |
+----+-------------+-------------+--------+----------------------+--------------+---------+----------------------------------+--------+----------------------------------------------+
|  1 | SIMPLE      | jobs        | ref    | PRIMARY,active_index | active_index | 1       | const                            | 468958 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | jobs_skills | ref    | PRIMARY              | PRIMARY      | 4       | 557574_prod.jobs.id              |      1 | Using where; Using index                     |
|  1 | SIMPLE      | skills      | eq_ref | PRIMARY              | PRIMARY      | 4       | 557574_prod.jobs_skills.skill_id |      1 | Using where                                  |
+----+-------------+-------------+--------+----------------------+--------------+---------+----------------------------------+--------+----------------------------------------------+

và đây là các CREATE TABLEbáo cáo cho các bảng có liên quan:

| jobs  | CREATE TABLE `jobs` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `user_id` int(10) unsigned NOT NULL,
  `title` varchar(40) NOT NULL,
  `description` text NOT NULL,
  `address_id` int(10) unsigned NOT NULL,
  `proximity` smallint(3) unsigned NOT NULL default '15',
  `job_payrate_id` tinyint(1) unsigned NOT NULL default '1',
  `payrate` int(10) unsigned NOT NULL,
  `start_date` int(10) unsigned NOT NULL,
  `job_start_id` tinyint(1) unsigned NOT NULL default '1',
  `duration` tinyint(1) unsigned NOT NULL COMMENT 'Full-time, Part-time, Flexible',
  `posting_date` int(10) unsigned NOT NULL,
  `revision_date` int(10) unsigned NOT NULL,
  `expiration` int(10) unsigned NOT NULL,
  `active` tinyint(1) unsigned NOT NULL default '1',
  `team_size` tinyint(2) unsigned NOT NULL default '1',
  `job_type_id` tinyint(1) unsigned NOT NULL default '1',
  `job_shift_id` tinyint(1) unsigned NOT NULL default '1',
  `job_visibility_id` tinyint(1) unsigned NOT NULL default '1',
  `position_count` smallint(5) unsigned NOT NULL default '1',
  `impressions` int(10) unsigned NOT NULL default '0',
  `clicks` int(10) unsigned NOT NULL default '0',
  `employer_email` varchar(100) NOT NULL default '',
  `job_source_id` smallint(6) unsigned NOT NULL default '0',
  `job_password` varchar(50) NOT NULL default '',
  PRIMARY KEY  (`id`),
  KEY `active_index` (`active`),
  KEY `user_id_index` (`user_id`),
  KEY `address_id_index` (`address_id`),
  KEY `posting_date_index` USING BTREE (`posting_date`)
) ENGINE=InnoDB AUTO_INCREMENT=875013 DEFAULT CHARSET=utf8

-

| jobs_skills | CREATE TABLE `jobs_skills` (
  `job_id` int(10) unsigned NOT NULL,
  `skill_id` int(10) unsigned NOT NULL,
  `required` tinyint(1) unsigned NOT NULL,
  PRIMARY KEY  (`job_id`,`skill_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

-

| skills | CREATE TABLE `skills` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `parent_id` int(10) unsigned NOT NULL,
  `name` varchar(35) NOT NULL default '',
  `description` varchar(250) NOT NULL,
  `valid` tinyint(1) unsigned NOT NULL default '0',
  `is_category` tinyint(1) unsigned NOT NULL default '0',
  `last_edited` int(10) unsigned NOT NULL default '0',
  `impressions` int(10) unsigned NOT NULL default '0',
  `clicks` int(10) unsigned NOT NULL default '0',
  `jobs` int(10) unsigned NOT NULL default '0',
  PRIMARY KEY  (`id`),
  KEY `name` (`name`),
  KEY `parent` (`parent_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2657 DEFAULT CHARSET=utf8 |

Giống như tôi đã nói, đây không phải là truy vấn duy nhất với vấn đề này, vì vậy mọi lời khuyên chung sẽ hữu ích nhất, mặc dù tôi sẽ không từ chối bất kỳ lời khuyên cụ thể nào cho truy vấn này.


Đây thực sự là một câu hỏi dành cho nhà phát triển rất tốt mà những người khác có thể cần biết để tránh các giới hạn được đặt bởi các công ty lưu trữ hoặc các DBA cao cấp. +1 cho câu hỏi này !!!
RolandoMySQLDBA

Câu trả lời:


5

Truy vấn ban đầu của bạn:

SELECT `skills`.`id`
FROM (`jobs_skills`)
JOIN `jobs` ON (`jobs`.`id` = `jobs_skills`.`job_id`)
JOIN `skills` ON (`skills`.`id` = `jobs_skills`.`skill_id`)
WHERE `jobs`.`job_visibility_id` = 1
AND `jobs`.`active` = 1
AND `skills`.`valid` = 1
AND `jobs_skills`.`skill_id` IN (96,101,103,108,121,2610,99,119,2607,102,104,112,113,122,1032,1488,2608,109,126,1438,2310,2318,2622,118,1046,1387,2609,100,116,123,2611,2612,2616,2618,114,127,1562,1587,1608,2276,2615,125,1070,1071,1161,1658,2613,2614,2617,105,110,111,120,1394,1435)
GROUP BY `jobs_skills`.`job_id`

Bạn cần điều khiển truy vấn theo cách mà bạn kiểm soát và quản lý vi mô các bảng tạm thời được tạo và kích thước của chúng. Chỉ dựa trên các mệnh đề THAM GIA, Ở ĐÂU và NHÓM THEO các mệnh đề, bạn cần thực hiện các thay đổi sau:

các công việc cần được lập chỉ mục trên job_visibility_id, active, id

Truy vấn cần thiết

(SELECT id job_id FROM jobs WHERE job_visibility_id=1 AND active=1 ORDER BY id)

kỹ năng cần được lập chỉ mục trên hợp lệ, id

Truy vấn cần thiết

(SELECT id skill_id FROM skills WHERE valid=1 ORDER BY id)

jobs_skills cần được lập chỉ mục trên skill_id, job_id

Truy vấn cần thiết

(SELECT job_id FROM jobs_skills WHERE skill_id IN (96,101,103,108,121,2610,99,119,2607,102,104,112,113,122,1032,1488,2608,109,126,1438,2310,2318,2622,118,1046,1387,2609,100,116,123,2611,2612,2616,2618,114,127,1562,1587,1608,2276,2615,125,1070,1071,1161,1658,2613,2614,2617,105,110,111,120,1394,1435) ORDER BY skill_id,job_id)

SQL để tạo các chỉ mục cần thiết

ALTER TABLE jobs ADD INDEX (job_visibility_id,active,id);
ALTER TABLE skills ADD INDEX (valid,id);
ALTER TABLE jobs_skills ADD INDEX (skill_id,job_id);

Bây giờ kết hợp các truy vấn con để tạo thành VOLTRON

SELECT skill_id
FROM (SELECT JS.*
FROM (SELECT skill_id,job_id FROM jobs_skills WHERE skill_id IN (96,101,103,108,121,2610,99,119,2607,102,104,112,113,122,1032,1488,2608,109,126,1438,2310,2318,2622,118,1046,1387,2609,100,116,123,2611,2612,2616,2618,114,127,1562,1587,1608,2276,2615,125,1070,1071,1161,1658,2613,2614,2617,105,110,111,120,1394,1435) ORDER BY skill_id,job_id) JS
INNER JOIN
(SELECT id job_id FROM jobs WHERE job_visibility_id=1 AND active=1 ORDER BY id) J
USING (job_id) INNER JOIN
(SELECT id skill_id FROM skills WHERE valid=1 ORDER BY id) S USING (skill_id)
) A
GROUP BY job_id;

Hãy thử một lần !!!

BTW nếu cú ​​pháp không chính xác, tôi sẽ cố gắng điều chỉnh nó !!!


tuyệt vời - Tôi có thể thấy phương pháp cơ bản để tạo các chỉ mục / truy vấn con này và có thể áp dụng nó cho các truy vấn gây ra sự cố khác. Cảm ơn!
JIS tone

@RolandMySQLDBA 'Bây giờ kết hợp các Truy vấn con để tạo thành LỚN' lol ... Cảm ơn vì sự hài hước. Làm cho ngày của tôi ...
StanleyJohns

Tôi nghĩ rằng nếu bạn vừa buộc truy vấn sử dụng chỉ mục PRIMARY cho bảng công việc, thì điều đó cũng có ích, THAM GIA công việc FORCE INDEX (PRIMARY), vì rõ ràng từ đầu ra EXPLAIN, vấn đề nằm ở chỗ MySQL không chọn chỉ mục tối ưu khi lọc các hàng từ bảng công việc. Bạn cũng có thể sử dụng STRAIGHT_JOIN để buộc MySQL tuân theo kế hoạch tham gia của bạn ,.
ovais.tariq

@ ovais.tariq FORCE INDEX không phải lúc nào cũng có ích trong hầu hết các trường hợp vì Trình tối ưu hóa truy vấn MySQL có thói quen bẩn thỉu tối ưu hóa các gợi ý chỉ mục do tạo các hàng, đề xuất và thậm chí các mệnh đề LIMIT biến mất trong không khí mỏng ( dba.stackexchange.com/questions / 1371 / Lát ). Các lợi ích của FORCE INDEX cũng bị ghi đè khi các mệnh đề THAM GIA được thực hiện trước và sau đó các mệnh đề WHERE được áp dụng cho các bảng tạm thời khổng lồ (không bao giờ được lập chỉ mục).
RolandoMySQLDBA

@RolandMySQLDBA., Có tham gia được thực hiện trước và theo thứ tự từ trái sang phải., Nhưng các chỉ mục giúp trình tối ưu hóa chọn bảng bên phải trước ,. Giả sử bạn có 3 bảng, t1, t2 và t3 ,. chúng sẽ được nối theo thứ tự t3xt2xt1, nếu t3 có thể được lọc bởi chỉ mục để có số lượng hàng ít nhất ,. Vì vậy, bằng cách sử dụng chỉ số lực, bạn thực sự chắc chắn rằng trình tối ưu hóa được nối từ trái sang phải theo cách tối ưu hóa ,.
ovais.tariq
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.