Tôi có một truy vấn cho tôi vấn đề và tôi không thể hiểu tại sao trình tối ưu hóa truy vấn của MySQL hoạt động theo cách của nó. Dưới đây là thông tin cơ bản:Tại sao MySQL không thể tối ưu hóa truy vấn này?
Tôi có 3 bảng. Hai là tương đối nhỏ và một là lớn.
Bảng 1 (rất nhỏ, 727 dòng):
CREATE TABLE
ipa
(
ipa_id
int (11) AUTO_INCREMENT NOT NULL,
ipa_code
int (11) DEFAULT NULL,
ipa_name
varchar (100) DEFAULT NULL,
payorcode
varchar (2) DEFAULT NULL,
compid
int (11) DEFAULT '2'
PRIMARY KEY (ipa_id
),
KEYipa_code
(ipa_code
)) ENGINE = MyISAM
Bảng 2 (smallish, 59.455 dòng):
CREATE TABLE
assign_ipa
(
assignid
int (11) NOT NULL AUTO_INCREMENT,
ipa_id
int (11) NOT NULL,
userid
int (11) NOT NUL L,
username
varchar (20) DEFAULT NULL,
compid
int (11) DEFAULT NULL,
PayorCode
char (10) DEFAULT NULL
PRIMARY KEY (assignid
),
UNIQUE KEYassignid
(assignid
,ipa_id
),
KEYipa_id
(ipa_id
)
) ENGINE = MyISAM
Bảng 3 (lớn, 24.711.730 hàng):
CREATE TABLE
master_final
(
IPA
int (11) DEFAULT NULL,
MbrCt
smallint (6) DEFAULT '0',
PayorCode
varchar (4) DEFAULT 'WC',
KEYidx_IPA
(IPA
)
) ENGINE = MyISAM DEFAULT
Bây giờ cho truy vấn. Tôi đang làm một cách 3-tham gia bằng cách sử dụng hai bảng nhỏ đầu tiên về cơ bản tập hợp các bảng lớn trên một trong những giá trị được lập chỉ mục của nó. Về cơ bản, tôi nhận được một danh sách các ID cho người dùng, SJOnes và truy vấn tệp lớn cho những ID đó.
mysql> giải thích
SELECT master_final.PayorCode, sum (master_final.Mbrct) AS MbrCt
TỪ master_final
INNER JOIN ipa ON ipa.ipa_code = master_final.IPA
INNER JOIN assign_ipa ON ipa.ipa_id = assign_ipa.ipa_id
ĐÂU assign_ipa.username = 'SJones'
GROUP BY master_final.PayorCode, master_final.ipa \ G;
* ** * ** * ** * ** * 1. hàng * ** * ** * ** * * * *
id: 1
select_type: SIMPLE
bảng: master_final
loại: TẤT CẢ
possible_keys: idx_IPA
chính: NULL
key_len: NULL
ref: NULL
hàng:
thêm: Sử dụng tạm thời; Sử dụng filesort
* ** * ** * ** * ** * 2. hàng * ** * ** * ** * ** *
id: 1
select_type: SIMPLE
bảng: ipa
loại: ref
possible_keys: TIỂU, ipa_code
chính: ipa_code
key_len: 5
ref: wc_test.master_final.IPA
hàng: 1
tắm: Sử dụng nơi
* ** * ** * ** * ** * 3.hàng * ** * ** * ** * ** *
id: 1
select_type: SIMPLE
bảng: assign_ipa
loại: ref
possible_keys: ipa_id
khóa: ipa_id
key_len: 4
ref: wc_test.ipa .ipa_id
hàng: 37
Extra: (! như 30 phút) Sử dụng nơi
3 hàng trong set (0.00 sec)
Truy vấn này sẽ mãi mãi. Tuyên bố giải thích cho tôi biết tại sao, nó thực hiện quét toàn bộ bảng trên bảng lớn mặc dù có một chỉ số hoàn toàn tốt. Nó không sử dụng nó. Tôi không hiểu điều này. Tôi có thể xem xét truy vấn và thấy rằng nó chỉ cần truy vấn một vài ID từ bảng lớn. Nếu tôi có thể làm điều đó, tại sao không thể tối ưu hóa của MySQL làm điều đó?
Để minh họa, sau đây là các ID kết hợp với 'SJones':
mysql> select Tên truy nhập, ipa_id từ assign_ipa nơi username = 'SJones';
+ ---------- + -------- +
| tên người dùng | ipa_id |
+ ---------- + -------- +
| SJones | 688 |
| SJones | 689 |
+ ---------- + -------- +
2 hàng in set (0.02 giây)
Bây giờ, tôi có thể viết lại truy vấn thay thế các giá trị ipa_id cho tên người dùng trong mệnh đề where. Đối với tôi, điều này tương đương với truy vấn ban đầu. MySQL thấy nó khác đi. Nếu tôi làm điều này, trình tối ưu hóa sử dụng chỉ mục trên bảng lớn.
mysql> giải thích
CHỌN master_final.PayorCode, sum (master_final.Mbrct) AS MbrCt
TỪ master_final
INNER JOIN ipa ON ipa.ipa_code = master_final.IPA
INNER JOIN assign_ipa ON ipa.ipa_id = assign_ipa.ipa_id
* WHERE assign_ipa.ipa_id trong ('688', '689') *
GROUP BY master_final.PayorCode, master_final.ipa \ G;
* ** * ** * ** * ** * 1.hàng * ** * ** * ** * ** *
id: 1
select_type: SIMPLE
bảng: ipa
loại: phạm vi
possible_keys: PRIMARY, ipa_code
khóa: PRIMARY
key_len: 4
ref: NULL
hàng: 2
Thêm: Sử dụng vị trí; Sử dụng tạm thời; Sử dụng filesort
* ** * ** * ** * ** * 2. hàng * ** * ** * ** * ** *
id: 1
select_type: SIMPLE
bảng: assign_ipa
loại: ref
possible_keys: ipa_id
chính: ipa_id
key_len: 4
ref: wc_test.ipa.ipa_id
hàng: 37
tắm: Sử dụng nơi
* ** * ** * ** * ** * 3. hàng * ** * ** * ** * ** *
id: 1
select_type: SIMPLE
bảng: master_final
loại: ref
possible_keys: idx_IPA
khóa: idx_IPA
key_len: 5
ref: wc_test.ipa.ipa_code
hàng:
tắm: Sử dụng nơi
3 hàng trong set (0.00 sec)
Điều duy nhất tôi đã thay đổi là một mệnh đề where mà thậm chí không trực tiếp đánh vào cái bàn lớn. Tuy nhiên, trình tối ưu hóa sử dụng chỉ mục 'idx_IPA' trên bảng lớn và quét toàn bộ bảng không còn được sử dụng nữa. Truy vấn khi viết lại như thế này rất nhanh.
OK, đó là rất nhiều nền tảng. Bây giờ câu hỏi của tôi. Tại sao mệnh đề where lại quan trọng với trình tối ưu hóa? Hoặc mệnh đề where sẽ trả về cùng một tập kết quả từ bảng nhỏ hơn, nhưng tôi nhận được các kết quả khác nhau đáng kể tùy thuộc vào kết quả tôi sử dụng. Rõ ràng, tôi muốn sử dụng mệnh đề where chứa tên người dùng thay vì cố gắng chuyển tất cả các ID liên quan đến truy vấn. Như được viết mặc dù, điều này là không thể?
- Ai đó có thể giải thích lý do tại sao điều này xảy ra?
- Tôi làm cách nào để viết lại truy vấn của mình để tránh quét toàn bộ bảng?
Cảm ơn bạn đã gắn bó với tôi. Tôi biết đó là một câu hỏi rất dài.
Tôi đã đọc một bài viết của một trong những nhà phát triển MySQL (một thời gian trước) rằng trình tối ưu hóa vẫn là một công việc đang được tiến hành - và sau đó chúng được Oracle hấp thụ. Bạn đã thử sử dụng "gợi ý" hoặc có thể di chuyển "assign_ipa.username = 'SJones'" vào JOIN? –