Cách tối ưu hóa CHỌN rất chậm với LEFT THAM GIA trên các bảng lớn


14

Tôi đã googling, tự giáo dục và tìm kiếm giải pháp trong nhiều giờ nhưng không có may mắn. Tôi tìm thấy một vài câu hỏi tương tự ở đây nhưng không phải trường hợp này.

Bảng của tôi:

  • người (~ 10 triệu hàng)
  • thuộc tính (vị trí, tuổi, ...)
  • liên kết (M: M) giữa người và thuộc tính (~ 40M hàng)

Đổ đầy ~ 280MB

Tình huống: Tôi cố gắng chọn tất cả id id ( person_id) từ một số vị trí ( location.attribute_value BETWEEN 3000 AND 7000), là một số giới tính ( gender.attribute_value = 1), được sinh ra trong một số năm ( bornyear.attribute_value BETWEEN 1980 AND 2000) và có màu mắt ( eyecolor.attribute_value IN (2,3)).

Đây là phù thủy truy vấn của tôi mất 3 ~ 4 phút. và tôi muốn tối ưu hóa:

SELECT person_id
FROM person
    LEFT JOIN attribute location ON location.attribute_type_id = 1 AND location.person_id = person.person_id
    LEFT JOIN attribute gender ON gender.attribute_type_id = 2 AND gender.person_id = person.person_id
    LEFT JOIN attribute bornyear ON bornyear.attribute_type_id = 3 AND bornyear.person_id = person.person_id
    LEFT JOIN attribute eyecolor ON eyecolor.attribute_type_id = 4 AND eyecolor.person_id = person.person_id
WHERE 1
    AND location.attribute_value BETWEEN 3000 AND 7000
    AND gender.attribute_value = 1
    AND bornyear.attribute_value BETWEEN 1980 AND 2000
    AND eyecolor.attribute_value IN (2,3)
LIMIT 100000;

Kết quả:

+-----------+
| person_id |
+-----------+
|       233 |
|       605 |
|       ... |
|   8702599 |
|   8703617 |
+-----------+
100000 rows in set (3 min 42.77 sec)

Giải thích mở rộng:

+----+-------------+----------+--------+---------------------------------------------+-----------------+---------+--------------------------+---------+----------+--------------------------+
| id | select_type | table    | type   | possible_keys                               | key             | key_len | ref                      | rows    | filtered | Extra                    |
+----+-------------+----------+--------+---------------------------------------------+-----------------+---------+--------------------------+---------+----------+--------------------------+
|  1 | SIMPLE      | bornyear | range  | attribute_type_id,attribute_value,person_id | attribute_value | 5       | NULL                     | 1265229 |   100.00 | Using where              |
|  1 | SIMPLE      | location | ref    | attribute_type_id,attribute_value,person_id | person_id       | 5       | test1.bornyear.person_id |       4 |   100.00 | Using where              |
|  1 | SIMPLE      | eyecolor | ref    | attribute_type_id,attribute_value,person_id | person_id       | 5       | test1.bornyear.person_id |       4 |   100.00 | Using where              |
|  1 | SIMPLE      | gender   | ref    | attribute_type_id,attribute_value,person_id | person_id       | 5       | test1.eyecolor.person_id |       4 |   100.00 | Using where              |
|  1 | SIMPLE      | person   | eq_ref | PRIMARY                                     | PRIMARY         | 4       | test1.location.person_id |       1 |   100.00 | Using where; Using index |
+----+-------------+----------+--------+---------------------------------------------+-----------------+---------+--------------------------+---------+----------+--------------------------+
5 rows in set, 1 warning (0.02 sec)

Hồ sơ:

+------------------------------+-----------+
| Status                       | Duration  |
+------------------------------+-----------+
| Sending data                 |  3.069452 |
| Waiting for query cache lock |  0.000017 |
| Sending data                 |  2.968915 |
| Waiting for query cache lock |  0.000019 |
| Sending data                 |  3.042468 |
| Waiting for query cache lock |  0.000043 |
| Sending data                 |  3.264984 |
| Waiting for query cache lock |  0.000017 |
| Sending data                 |  2.823919 |
| Waiting for query cache lock |  0.000038 |
| Sending data                 |  2.863903 |
| Waiting for query cache lock |  0.000014 |
| Sending data                 |  2.971079 |
| Waiting for query cache lock |  0.000020 |
| Sending data                 |  3.053197 |
| Waiting for query cache lock |  0.000087 |
| Sending data                 |  3.099053 |
| Waiting for query cache lock |  0.000035 |
| Sending data                 |  3.064186 |
| Waiting for query cache lock |  0.000017 |
| Sending data                 |  2.939404 |
| Waiting for query cache lock |  0.000018 |
| Sending data                 |  3.440288 |
| Waiting for query cache lock |  0.000086 |
| Sending data                 |  3.115798 |
| Waiting for query cache lock |  0.000068 |
| Sending data                 |  3.075427 |
| Waiting for query cache lock |  0.000072 |
| Sending data                 |  3.658319 |
| Waiting for query cache lock |  0.000061 |
| Sending data                 |  3.335427 |
| Waiting for query cache lock |  0.000049 |
| Sending data                 |  3.319430 |
| Waiting for query cache lock |  0.000061 |
| Sending data                 |  3.496563 |
| Waiting for query cache lock |  0.000029 |
| Sending data                 |  3.017041 |
| Waiting for query cache lock |  0.000032 |
| Sending data                 |  3.132841 |
| Waiting for query cache lock |  0.000050 |
| Sending data                 |  2.901310 |
| Waiting for query cache lock |  0.000016 |
| Sending data                 |  3.107269 |
| Waiting for query cache lock |  0.000062 |
| Sending data                 |  2.937373 |
| Waiting for query cache lock |  0.000016 |
| Sending data                 |  3.097082 |
| Waiting for query cache lock |  0.000261 |
| Sending data                 |  3.026108 |
| Waiting for query cache lock |  0.000026 |
| Sending data                 |  3.089760 |
| Waiting for query cache lock |  0.000041 |
| Sending data                 |  3.012763 |
| Waiting for query cache lock |  0.000021 |
| Sending data                 |  3.069694 |
| Waiting for query cache lock |  0.000046 |
| Sending data                 |  3.591908 |
| Waiting for query cache lock |  0.000060 |
| Sending data                 |  3.526693 |
| Waiting for query cache lock |  0.000076 |
| Sending data                 |  3.772659 |
| Waiting for query cache lock |  0.000069 |
| Sending data                 |  3.346089 |
| Waiting for query cache lock |  0.000245 |
| Sending data                 |  3.300460 |
| Waiting for query cache lock |  0.000019 |
| Sending data                 |  3.135361 |
| Waiting for query cache lock |  0.000021 |
| Sending data                 |  2.909447 |
| Waiting for query cache lock |  0.000039 |
| Sending data                 |  3.337561 |
| Waiting for query cache lock |  0.000140 |
| Sending data                 |  3.138180 |
| Waiting for query cache lock |  0.000090 |
| Sending data                 |  3.060687 |
| Waiting for query cache lock |  0.000085 |
| Sending data                 |  2.938677 |
| Waiting for query cache lock |  0.000041 |
| Sending data                 |  2.977974 |
| Waiting for query cache lock |  0.000872 |
| Sending data                 |  2.918640 |
| Waiting for query cache lock |  0.000036 |
| Sending data                 |  2.975842 |
| Waiting for query cache lock |  0.000051 |
| Sending data                 |  2.918988 |
| Waiting for query cache lock |  0.000021 |
| Sending data                 |  2.943810 |
| Waiting for query cache lock |  0.000061 |
| Sending data                 |  3.330211 |
| Waiting for query cache lock |  0.000025 |
| Sending data                 |  3.411236 |
| Waiting for query cache lock |  0.000023 |
| Sending data                 | 23.339035 |
| end                          |  0.000807 |
| query end                    |  0.000023 |
| closing tables               |  0.000325 |
| freeing items                |  0.001217 |
| logging slow query           |  0.000007 |
| logging slow query           |  0.000011 |
| cleaning up                  |  0.000104 |
+------------------------------+-----------+
100 rows in set (0.00 sec)

Cấu trúc bảng:

CREATE TABLE `attribute` (
  `attribute_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `attribute_type_id` int(11) unsigned DEFAULT NULL,
  `attribute_value` int(6) DEFAULT NULL,
  `person_id` int(11) unsigned DEFAULT NULL,
  PRIMARY KEY (`attribute_id`),
  KEY `attribute_type_id` (`attribute_type_id`),
  KEY `attribute_value` (`attribute_value`),
  KEY `person_id` (`person_id`)
) ENGINE=MyISAM AUTO_INCREMENT=40000001 DEFAULT CHARSET=utf8;

CREATE TABLE `person` (
  `person_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `person_name` text CHARACTER SET latin1,
  PRIMARY KEY (`person_id`)
) ENGINE=MyISAM AUTO_INCREMENT=20000001 DEFAULT CHARSET=utf8;

Truy vấn đã được thực hiện trên máy chủ ảo DigitalOcean với SSD và RAM 1GB.

Tôi giả sử có thể có vấn đề với thiết kế cơ sở dữ liệu. Bạn có bất cứ đề nghị để thiết kế tình huống này tốt hơn xin vui lòng? Hay chỉ để điều chỉnh lựa chọn ở trên?


4
Đó là cái giá bạn phải trả cho thiết kế EAV. Bạn có thể muốn thử một chỉ mục tổng hợp trênattribute (person_id, attribute_type_id, attribute_value)
mustaccio

1
Tôi sẽ thử thêm các chỉ mục này: (attribute_type_id, attribute_value, person_id)(attribute_type_id, person_id, attribute_value)
ypercubeᵀᴹ

5
Và sử dụng InnoDB, vứt bỏ MyISAM. Đây là năm 2015, MyiSAM đã chết từ lâu.
ypercubeᵀᴹ

2
Điều đầu tiên - loại bỏ tham gia TRÁI, nó không có tác dụng khi bạn sử dụng tất cả các bảng trong điều kiện WHERE của mình, chuyển tất cả các tham gia sang tham gia INNER một cách hiệu quả (trình tối ưu hóa có thể hiểu và tối ưu hóa điều đó nhưng tốt hơn là không làm khó hơn ). Điều thứ hai - vô hiệu hóa bộ đệm truy vấn trừ khi bạn có lý do chính đáng để sử dụng nó (= bạn đã kiểm tra nó và đo lường rằng nó giúp bạn)
jkavalik

2
OT: Không có gì lạ khi bạn sử dụng GIỚI HẠN ĐẶT HÀNG B BYNG? Điều này sẽ trả lại một số hàng 100000 ngẫu nhiên?
ioust5041

Câu trả lời:


6

Chọn một vài thuộc tính để bao gồm trong person. Lập chỉ mục chúng trong một vài kết hợp - sử dụng chỉ mục tổng hợp, không phải chỉ mục cột đơn.

Đó thực chất là cách duy nhất để thoát khỏi hiệu suất của EAV, đó là nơi bạn đang ở.

Ở đây có nhiều thảo luận hơn: http://mysql.rjweb.org/doc.php/eav bao gồm đề xuất sử dụng JSON thay vì bảng giá trị khóa.


3

Thêm phân vào attributecho:

  • (person_id, attribute_type_id, attribute_value)
  • (attribute_type_id, attribute_value, person_id)

Giải trình

Với thiết kế hiện tại của bạn EXPLAINhy vọng truy vấn của bạn để kiểm tra 1,265,229 * 4 * 4 * 4 = 80,974,656các hàng trong attribute. Bạn có thể giảm số lượng này bằng cách thêm một chỉ số tổng hợp trên attributecho (person_id, attribute_type_id). Sử dụng chỉ số này truy vấn của bạn sẽ chỉ xem xét 1 thay vì 4 hàng cho mỗi location, eyecolorgender.

Bạn có thể mở rộng chỉ mục đó để bao gồm attribute_type_valuecả : (person_id, attribute_type_id, attribute_value). Điều này sẽ biến chỉ mục này thành một chỉ mục bao trùm cho truy vấn này, điều này cũng sẽ cải thiện hiệu suất.

Hơn nữa, việc thêm một chỉ mục trên (attribute_type_id, attribute_value, person_id)(một lần nữa là một chỉ số bao gồm bằng cách bao gồm person_id) sẽ cải thiện hiệu suất hơn là chỉ sử dụng một chỉ mục về attribute_valuenơi sẽ phải kiểm tra nhiều hàng hơn. Trong trường hợp này, nó sẽ nhanh bước đầu tiên trong phần giải thích của bạn: chọn một phạm vi từ bornyear.

Sử dụng hai phân này đã giảm thời gian thực hiện truy vấn của bạn trên hệ thống của tôi từ ~ 2.0 s xuống ~ 0.2 s với đầu ra giải thích trông như thế này:

+----+-------------+----------+--------+-------------------------------------+-------------------+---------+--------------------------------+---------+----------+--------------------------+
| id | select_type | table    | type   | possible_keys                       | key               | key_len | ref                            |    rows | filtered | Extra                    |
+----+-------------+----------+--------+-------------------------------------+-------------------+---------+--------------------------------+---------+----------+--------------------------+
|  1 | SIMPLE      | bornyear | range  | person_type_value,type_value_person | type_value_person |       9 |                                | 1861881 |   100.00 | Using where; Using index |
|  1 | SIMPLE      | location | ref    | person_type_value,type_value_person | person_type_value |       8 | bornyear.person_id,const       |       1 |   100.00 | Using where; Using index |
|  1 | SIMPLE      | eyecolor | ref    | person_type_value,type_value_person | person_type_value |       8 | bornyear.person_id,const       |       1 |   100.00 | Using where; Using index |
|  1 | SIMPLE      | gender   | ref    | person_type_value,type_value_person | person_type_value |      13 | bornyear.person_id,const,const |       1 |   100.00 | Using index              |
|  1 | SIMPLE      | person   | eq_ref | PRIMARY                             | PRIMARY           |       4 | bornyear.person_id             |       1 |   100.00 | Using index              |
+----+-------------+----------+--------+-------------------------------------+-------------------+---------+--------------------------------+---------+----------+--------------------------+

1
Cảm ơn câu trả lời và giải thích sâu rộng. Tôi đã làm tất cả những gì bạn đề cập nhưng truy vấn vẫn mất ~ 2 phút. Xin vui lòng, bạn đang sử dụng loại bảng nào (innodb, myisam) và truy vấn chính xác nào được thực hiện?
Martin

1
Khác với việc thêm phân tôi đã sử dụng chính xác cùng dữ liệu và định nghĩa bạn đã làm, vì vậy tôi đã sử dụng MyISAM. Tôi đã thay đổi dòng đầu tiên của truy vấn của bạn thành SELECT person.person_idvì nếu không nó sẽ không chạy, rõ ràng. Bạn đã làm ANALYZE TABLE attributesau khi thêm phân? Bạn có thể muốn thêm EXPLAINđầu ra mới của mình (sau khi thêm phân) vào câu hỏi của bạn.
wolfgangwalther

3

Tôi giả sử có thể có vấn đề với thiết kế cơ sở dữ liệu.

Bạn đang sử dụng một thiết kế được gọi là Thực thể-Thuộc tính-Giá trị, thường hoạt động kém, tốt, theo thiết kế.

Bạn có bất cứ đề nghị để thiết kế tình huống này tốt hơn xin vui lòng?

Cách quan hệ cổ điển để thiết kế này sẽ tạo một bảng riêng cho từng thuộc tính. Nói chung, bạn có thể có các bảng riêng biệt: location, gender, bornyear, eyecolor.

Những điều sau đây phụ thuộc vào việc một số thuộc tính nhất định luôn được xác định cho một người hay không. Và, cho dù một người có thể chỉ có một giá trị của một thuộc tính. Ví dụ, thường thì người đó chỉ có một giới tính. Trong thiết kế hiện tại của bạn, không có gì ngăn bạn thêm ba hàng cho cùng một người với các giá trị khác nhau cho giới tính trong đó. Bạn cũng có thể đặt giá trị giới tính không phải là 1 hoặc 2, nhưng với một số số không có ý nghĩa, như 987 và không có ràng buộc nào trong cơ sở dữ liệu sẽ ngăn chặn nó. Nhưng, đây là một vấn đề riêng biệt khác của việc duy trì tính toàn vẹn dữ liệu với thiết kế EAV.

Nếu bạn luôn biết giới tính của người đó, thì việc đặt nó vào một bảng riêng biệt sẽ tốt hơn và tốt hơn là có một cột không null GenderIDtrong personbảng, đó sẽ là một khóa ngoại đối với bảng tra cứu với danh sách tất cả các giới tính có thể và tên của họ. Nếu bạn biết giới tính của người đó hầu hết thời gian, nhưng không phải lúc nào cũng vậy, bạn có thể đặt cột này thành null và đặt thành NULLkhi thông tin không có sẵn. Nếu hầu hết thời gian giới tính của người đó không được biết đến, thì tốt hơn là nên có một bảng riêng genderliên kết đến person1: 1 và chỉ có các hàng dành cho những người có giới tính đã biết.

Những cân nhắc tương tự áp dụng cho eyecolorbornyear- người không có khả năng có hai giá trị cho một eyecolorhoặc bornyear.

Nếu một người có thể có một vài giá trị cho một thuộc tính, thì bạn chắc chắn sẽ đặt nó vào một bảng riêng biệt. Ví dụ, không có gì lạ khi một người có nhiều địa chỉ (nhà, cơ quan, bưu chính, kỳ nghỉ, v.v.), vì vậy bạn sẽ liệt kê tất cả chúng trong một bảng location. Bảng personlocationsẽ được liên kết 1: M.


Hay chỉ để điều chỉnh lựa chọn ở trên?

Nếu sử dụng thiết kế EAV, thì ít nhất tôi sẽ làm như sau.

  • Set cột attribute_type_id, attribute_value, person_idđể NOT NULL.
  • Thiết lập khóa ngoại liên kết attribute.person_idvới person.person_id.
  • Tạo một chỉ mục trên ba cột (attribute_type_id, attribute_value, person_id). Thứ tự của các cột là quan trọng ở đây.
  • Theo như tôi biết, MyISAM không tôn trọng các khóa ngoại, vì vậy đừng sử dụng nó, thay vào đó hãy sử dụng InnoDB.

Tôi sẽ viết truy vấn như thế này. Sử dụng INNERthay vì LEFTtham gia và viết rõ ràng truy vấn con cho từng thuộc tính để cung cấp cho trình tối ưu hóa tất cả các cơ hội sử dụng chỉ mục.

SELECT person.person_id
FROM
    person
    INNER JOIN
    (
        SELECT attribute.person_id
        FROM attribute
        WHERE attribute_type_id = 1
            AND location.attribute_value BETWEEN 3000 AND 7000
    ) AS location ON location.person_id = person.person_id
    INNER JOIN
    (
        SELECT attribute.person_id
        FROM attribute
        WHERE attribute_type_id = 2
            AND location.attribute_value = 1
    ) AS gender ON gender.person_id = person.person_id
    INNER JOIN
    (
        SELECT attribute.person_id
        FROM attribute
        WHERE attribute_type_id = 3
            AND location.attribute_value BETWEEN 1980 AND 2000
    ) AS bornyear ON bornyear.person_id = person.person_id
    INNER JOIN
    (
        SELECT attribute.person_id
        FROM attribute
        WHERE attribute_type_id = 4
            AND location.attribute_value IN (2, 3)
    ) AS eyecolor ON eyecolor.person_id = person.person_id
LIMIT 100000;

Ngoài ra, nó có thể là giá trị phân vùng các attributebảng bằng attribute_type_id.


Hiệu suất thận trọng: JOIN ( SELECT ... )không tối ưu hóa tốt. JOINingtrực tiếp để bảng hoạt động tốt hơn (nhưng vẫn còn vấn đề).
Rick James

2

Tôi hy vọng tôi tìm thấy một giải pháp đầy đủ. Nó lấy cảm hứng từ bài viết này .

Câu trả lời ngắn:

  1. Tôi đã tạo 1 bảng với tất cả các thuộc tính. Một cột cho một thuộc tính. Cộng với cột khóa chính.
  2. Các giá trị thuộc tính được lưu trữ trong các ô văn bản (để tìm kiếm toàn văn bản) ở định dạng giống như CSV.
  3. Tạo các chỉ mục toàn văn. Trước đó, điều quan trọng là phải đặt ft_min_word_len=1(cho MyISAM) trong [mysqld]phần và innodb_ft_min_token_size=1(cho InnoDb) trong my.cnftệp, khởi động lại dịch vụ mysql.
  4. Ví dụ tìm kiếm: SELECT * FROM person_index WHERE MATCH(attribute_1) AGAINST("123 456 789" IN BOOLEAN MODE) LIMIT 1000ở đâu 123, 456a 789là ID mà những người nên có liên quan attribute_1. Truy vấn này mất dưới 1 giây.

Câu trả lời chi tiết:

Bước 1. Tạo bảng với các chỉ mục fulltext. InnoDb hỗ trợ các chỉ mục fulltext từ MySQL 5.7 vì vậy nếu bạn sử dụng 5.5 hoặc 5.6, bạn nên sử dụng MyISAM. Đôi khi nó còn nhanh hơn cho việc tìm kiếm FT so với InnoDb.

CREATE TABLE `person_attribute_ft` (
  `person_id` int(11) NOT NULL,
  `attr_1` text,
  `attr_2` text,
  `attr_3` text,
  `attr_4` text,
  PRIMARY KEY (`person_id`),
  FULLTEXT KEY `attr_1` (`attr_1`),
  FULLTEXT KEY `attr_2` (`attr_2`),
  FULLTEXT KEY `attr_3` (`attr_3`),
  FULLTEXT KEY `attr_4` (`attr_4`),
  FULLTEXT KEY `attr_12` (`attr_1`,`attr_2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

Bước 2. Chèn dữ liệu từ bảng EAV (thực thể-thuộc tính-giá trị). Ví dụ được nêu trong câu hỏi, nó có thể được thực hiện với 1 SQL đơn giản:

INSERT IGNORE INTO `person_attribute_ft`
SELECT
    p.person_id,
    (SELECT GROUP_CONCAT(a.attribute_value SEPARATOR ' ') FROM attribute a WHERE a.attribute_type_id = 1 AND a.person_id = p.person_id LIMIT 10) attr_1,
    (SELECT GROUP_CONCAT(a.attribute_value SEPARATOR ' ') FROM attribute a WHERE a.attribute_type_id = 2 AND a.person_id = p.person_id LIMIT 10) attr_2,
    (SELECT GROUP_CONCAT(a.attribute_value SEPARATOR ' ') FROM attribute a WHERE a.attribute_type_id = 3 AND a.person_id = p.person_id LIMIT 10) attr_3,
    (SELECT GROUP_CONCAT(a.attribute_value SEPARATOR ' ') FROM attribute a WHERE a.attribute_type_id = 4 AND a.person_id = p.person_id LIMIT 10) attr_4
FROM person p

Kết quả sẽ giống như thế này:

mysql> select * from person_attribute_ft limit 10;
+-----------+--------+--------+--------+--------+
| person_id | attr_1 | attr_2 | attr_3 | attr_4 |
+-----------+--------+--------+--------+--------+
|         1 | 541    | 2      | 1927   | 3      |
|         2 | 2862   | 2      | 1939   | 4      |
|         3 | 6573   | 2      | 1904   | 2      |
|         4 | 2432   | 1      | 2005   | 2      |
|         5 | 2208   | 1      | 1995   | 4      |
|         6 | 8388   | 2      | 1973   | 1      |
|         7 | 107    | 2      | 1909   | 4      |
|         8 | 5161   | 1      | 2005   | 1      |
|         9 | 8022   | 2      | 1953   | 4      |
|        10 | 4801   | 2      | 1900   | 3      |
+-----------+--------+--------+--------+--------+
10 rows in set (0.00 sec)

Bước 3. Chọn từ bảng với truy vấn như thế này:

mysql> SELECT SQL_NO_CACHE *
    -> FROM `person_attribute_ft`
    -> WHERE 1 AND MATCH(attr_1) AGAINST ("3000 3001 3002 3003 3004 3005 3006 3007" IN BOOLEAN MODE)
    -> AND MATCH(attr_2) AGAINST ("1" IN BOOLEAN MODE)
    -> AND MATCH(attr_3) AGAINST ("1980 1981 1982 1983 1984" IN BOOLEAN MODE)
    -> AND MATCH(attr_4) AGAINST ("2,3" IN BOOLEAN MODE)
    -> LIMIT 10000;
+-----------+--------+--------+--------+--------+
| person_id | attr_1 | attr_2 | attr_3 | attr_4 |
+-----------+--------+--------+--------+--------+
|     12131 | 3002   | 1      | 1982   | 2      |
|     51315 | 3007   | 1      | 1984   | 2      |
|    147283 | 3001   | 1      | 1984   | 2      |
|    350086 | 3005   | 1      | 1982   | 3      |
|    423907 | 3004   | 1      | 1982   | 3      |
... many rows ...
|   9423907 | 3004   | 1      | 1982   | 3      |
|   9461892 | 3007   | 1      | 1982   | 2      |
|   9516361 | 3006   | 1      | 1980   | 2      |
|   9813933 | 3005   | 1      | 1982   | 2      |
|   9986892 | 3003   | 1      | 1981   | 2      |
+-----------+--------+--------+--------+--------+
90 rows in set (0.17 sec)

Truy vấn chọn tất cả các hàng:

  • khớp với ít nhất một trong số các ID này trong attr_1:3000, 3001, 3002, 3003, 3004, 3005, 3006 or 3007
  • VÀ đồng thời khớp 1trong attr_2(cột này thể hiện giới tính vì vậy nếu giải pháp này được tùy chỉnh, thì nó phải smallint(1)có chỉ số đơn giản, v.v ...)
  • VÀ đồng thời khớp với ít nhất một 1980, 1981, 1982, 1983 or 1984trongattr_3
  • VÀ đồng thời khớp 2hoặc 3trongattr_4

Phần kết luận:

Tôi biết giải pháp này không hoàn hảo và lý tưởng cho nhiều tình huống nhưng có thể được sử dụng như một giải pháp thay thế tốt cho thiết kế bảng EAV.

Tôi hy vọng nó sẽ giúp được ai đó.


1
Tôi thấy rất khó có khả năng thiết kế này sẽ hoạt động tốt hơn thiết kế ban đầu của bạn với các chỉ mục tổng hợp. Những bài kiểm tra bạn đã làm để so sánh chúng?
ypercubeᵀᴹ

0

Hãy thử sử dụng gợi ý chỉ mục truy vấn có vẻ phù hợp

Gợi ý chỉ số Mysql


1
Gợi ý có thể giúp một phiên bản của truy vấn, nhưng sau đó làm tổn thương một phiên bản khác. Lưu ý rằng Trình tối ưu hóa đã chọn sinh ra là bảng đầu tiên tốt nhất, có lẽ bởi vì nếu được lọc ra các hàng không mong muốn nhất.
Rick James
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.