Büyük masalar üzerinde LEFT JOIN'lerle çok yavaş SEÇİM nasıl optimize edilir


15

Ben googling, kendi kendine eğitim ve saatlerce ama şanssız bir çözüm arıyor. Burada birkaç benzer soru buldum ama bu davada değil.

Tablolarım:

  • kişiler (~ 10 milyon satır)
  • özellikler (konum, yaş, ...)
  • kişiler ve nitelikler arasındaki bağlantılar (M: M) (~ 40M satırlar)

Tam çöp ~ 280MB

Durum:person_id Bazı yerlerden ( location.attribute_value BETWEEN 3000 AND 7000), bazı cinsiyetlerden ( gender.attribute_value = 1), bazı yıllarda doğan ( bornyear.attribute_value BETWEEN 1980 AND 2000) ve bazı gözlerin rengine ( eyecolor.attribute_value IN (2,3)) sahip olan tüm kişi kimliklerini ( ) seçmeye çalışıyorum .

Bu benim sorgu cadı 3 ~ 4 dk tooks . ve optimize etmek istiyorum:

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;

Sonuç:

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

Genişletilmiş açıklama:

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

profil oluşturma:

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

Tablo yapıları:

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;

Sorgu SSD ve 1GB RAM ile DigitalOcean sanal sunucusunda gerçekleştirildi.

Veritabanı tasarımı ile ilgili bir sorun olabileceğini düşünüyorum. Bu durumu daha iyi tasarlamak için herhangi bir öneriniz var mı? Ya da sadece yukarıdaki seçimi ayarlamak için?


4
EAV tasarımı için ödediğiniz bedel budur. Kompozit endeksi denemek isteyebilirsinizattribute (person_id, attribute_type_id, attribute_value)
mustaccio

1
Bu dizinleri eklemeyi (attribute_type_id, attribute_value, person_id)(attribute_type_id, person_id, attribute_value)
denerdim

5
Ve InnoDB'yi kullanın, MyISAM'ı atın. Bu 2015, MyiSAM çoktan öldü.
ypercubeᵀᴹ

2
İlk şey - SOL birleştirmeden kurtulun, WHERE durumunuzdaki tüm tabloları kullandığınız için hiçbir etkisi yoktur, tüm birleştirmeleri etkili bir şekilde INNER birleşimlerine dönüştürür (optimizer bunu anlayabilmeli ve optimize edebilmelidir, ancak daha zorlaştırmamak için daha iyi olmalıdır) ). İkinci şey - kullanmak için güçlü bir nedeniniz yoksa sorgu önbelleğini devre dışı bırakın (= test ettiniz ve size yardımcı olduğunu
ölçtünüz

2
OT: SİPARİŞ VERMEDEN LİMİT kullanmanız garip değil mi? Bu bazı rastgele 100000 satır döndürür?
ibre5041

Yanıtlar:


8

Eklenecek birkaç özellik seçin person. Bunları birkaç kombinasyon halinde dizine ekleyin - tek sütunlu dizinleri değil, bileşik dizinleri kullanın.

Bu, esasen bulunduğunuz yer olan EAV-performansında berbat olmanın tek yoludur.

İşte daha fazla tartışma: http://mysql.rjweb.org/doc.php/eav , anahtar / değer tablosu yerine JSON kullanma önerisi de dahil.


3

Şunun için girinti ekle attribute:

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

açıklama

Mevcut tasarım ile EXPLAINsorgunuz 1,265,229 * 4 * 4 * 4 = 80,974,656satırları incelemek için bekliyor attribute. Bir ekleyerek bu sayısını azaltabilir bileşik endeks üzerinde attributeiçin (person_id, attribute_type_id). Bu dizini kullanarak sorgunuz location, eyecolorve öğelerinin her biri için 4 satır yerine yalnızca 1 değerini inceler gender.

Sen içerecek şekilde indeksi genişletmek olabilir attribute_type_valuede: (person_id, attribute_type_id, attribute_value). Bu, bu dizini bu sorgunun performansını da iyileştirecek bir kaplama dizinine dönüştürür .

Ayrıca, bir indeks eklemek (attribute_type_id, attribute_value, person_id)(yine kapsayan bir indeks eklemek person_id), sadece attribute_valuedaha fazla satırın incelenmesi gereken bir indeks kullanarak performansı arttırmalıdır . Bu durumda, açıklamanızdaki ilk adımı sabitleyecektir: bir aralık seçme bornyear.

Bu iki girintiyi kullanarak, sistemimdeki sorgunuzun yürütme süresini ~ 2.0 sn'den ~ 0.2 sn'ye düşürerek açıklama çıktısı şuna benzer:

+----+-------------+----------+--------+-------------------------------------+-------------------+---------+--------------------------------+---------+----------+--------------------------+
| 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
Kapsamlı cevap ve açıklama için teşekkürler. Bahsettiğin her şeyi yaptım ama sorgu hala ~ 2 dak. Lütfen, hangi tablo türünü (innodb, myisam) kullanıyorsunuz ve hangi sorguyu gerçekleştiriyorsunuz?
Martin

1
Indeces eklemek dışında yaptığınız aynı veri ve tanımları kullandım, bu yüzden MyISAM kullandım. Sorgunuzun ilk satırını olarak değiştirdim, SELECT person.person_idçünkü aksi takdirde çalışmaz. Tek yapmanız mı ANALYZE TABLE attributeyönelimler belirlenmiştir ekledikten sonra? EXPLAINSorunuza yeni çıktınızı da (girinti ekledikten sonra) eklemek isteyebilirsiniz.
wolfgangwalther

3

Veritabanı tasarımı ile ilgili bir sorun olabileceğini düşünüyorum.

Tasarım gereği genellikle kötü, iyi performans gösteren Varlık-Öznitelik-Değer tasarımını kullanıyorsunuz.

Bu durumu daha iyi tasarlamak için herhangi bir öneriniz var mı?

Bunu tasarlamanın klasik ilişkisel yolu, her özellik için ayrı bir tablo oluşturmak olacaktır. Genel olarak, bu ayrı tablolar olabilir: location, gender, bornyear, eyecolor.

Aşağıdakiler, belirli niteliklerin bir kişi için her zaman tanımlanıp tanımlanmadığına bağlıdır. Ve bir kişinin bir nitelik için sadece bir değere sahip olup olamayacağı. Örneğin, genellikle kişinin sadece bir cinsiyeti vardır. Mevcut tasarımınızda hiçbir şey, aynı kişi için cinsiyet için farklı değerlere sahip üç satır eklemenizi engellemez. Ayrıca, cinsiyet değerini 1 veya 2 olarak değil, 987 gibi anlamlı olmayan bir sayıya ayarlayabilirsiniz ve veritabanında bunu engelleyecek bir kısıtlama yoktur. Ancak bu, EAV tasarımı ile veri bütünlüğünü korumaya yönelik bir başka ayrı konudur.

Her zaman kişinin cinsiyetini biliyorsanız, o zaman ayrı bir tabloda koymak için biraz mantıklı ve boş olmayan bir sütun sahibi olmak için daha iyidir GenderIDiçinde personlistesiyle arama tablosuna bir yabancı anahtar olacağını masa, tüm olası cinsiyetler ve isimleri. Kişinin cinsiyetini çoğu zaman biliyor, ancak her zaman değil, bu sütunu boş bırakabilir ve NULLbilgi mevcut olmadığında ayarlayabilirsiniz . Çoğu zaman kişinin cinsiyeti bilinmiyorsa, o zaman 1: 1'e genderbağlanan personve sadece cinsiyeti bilinen kişiler için satırları olan ayrı bir tabloya sahip olmak daha iyi olabilir .

Benzer düşünceler için geçerlidir eyecolorve bornyear- kişinin bir eyecolorveya için iki değere sahip olması olası değildir bornyear.

Bir kişinin bir özellik için çeşitli değerlere sahip olması mümkünse, kesinlikle ayrı bir tabloya yerleştirirsiniz. Örneğin, bir kişinin birkaç adresi (ev, iş, posta, tatil vb.) Olması nadir değildir, bu yüzden hepsini bir tabloda listelersiniz location. Tablolar personve location1: M.


Ya da sadece yukarıdaki seçimi ayarlamak için?

EAV tasarımını kullanıyorsanız, en azından aşağıdakileri yaparım.

  • Set sütunlar attribute_type_id, attribute_value, person_idiçin NOT NULL.
  • Bu linkler yabancı anahtar kurun attribute.person_idile person.person_id.
  • Üç sütunda bir dizin oluşturun (attribute_type_id, attribute_value, person_id). Burada sütunların sırası önemlidir.
  • Bildiğim kadarıyla, MyISAM yabancı anahtarları onurlandırmıyor, bu yüzden kullanmayın, bunun yerine InnoDB'yi kullanın.

Sorguyu böyle yazardım. Birleştirme INNERyerine kullanın LEFTve her bir öznitelik için açıkça alt sorguyu yazarak en iyileştiriciye dizini kullanma şansı verin.

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;

Ayrıca, buna değer olabilir bölünmesiattribute ile tablo attribute_type_id.


Performans uyarısı: JOIN ( SELECT ... )iyi optimize etmez. JOINingdoğrudan masaya daha iyi çalışır (ancak yine de sorunludur).
Rick James

3

Umarım yeterli bir çözüm buldum. Bu makaleden esinlenmiştir .

Kısa cevap:

  1. Tüm özellikleri ile 1 tablo oluşturdum. Bir özellik için bir sütun. Artı birincil anahtar sütunu.
  2. Özellik değerleri metin hücrelerinde (tam metin araması için) CSV benzeri biçimde depolanır.
  3. Tam metin dizinleri oluşturuldu. Bundan önce ft_min_word_len=1(MyISAM için) [mysqld]bölümünde ve innodb_ft_min_token_size=1(InnoDb için) my.cnfdosyada ayarlamak önemlidir , mysql hizmetini yeniden başlatın.
  4. Arama örneği: SELECT * FROM person_index WHERE MATCH(attribute_1) AGAINST("123 456 789" IN BOOLEAN MODE) LIMIT 1000nerede 123, 456a 789, kişilerin ilişkilendirilmesi gereken kimliklerdir attribute_1. Bu sorgu 1 saniyenin altında sürdü.

Ayrıntılı cevap:

Adım 1. Tam metin dizinleri ile tablo oluşturma. InnoDb, MySQL 5.7'den tam metin dizinlerini destekler, bu nedenle 5.5 veya 5.6 kullanıyorsanız MyISAM kullanmalısınız. FT araması için bazen InnoDb'den bile daha hızlıdır.

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

Adım 2. EAV (varlık-özellik-değer) tablosundan veri ekleyin. Örneğin söz konusu 1 basit SQL ile yapılabilir:

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

Sonuç böyle bir şey olmalı:

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)

Adım 3. Aşağıdaki gibi sorgu içeren tablodan seçin:

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)

Sorgu tüm satırları seçer:

  • şu kimliklerden en az biriyle eşleşen attr_1:3000, 3001, 3002, 3003, 3004, 3005, 3006 or 3007
  • VE aynı zamanda eşleştirme de 1içinde attr_2(bu sütunda temsil cinsiyeti bu çözüm özelleştirilmiş olsaydı, olması gerektiği böylece smallint(1)basit indeksi, vs ...)
  • AND aynı zamanda 1980, 1981, 1982, 1983 or 1984inattr_3
  • VE aynı zamanda eşleştirme de 2veya 3içindeattr_4

Sonuç:

Bu çözümün birçok durum için mükemmel ve ideal olmadığını biliyorum, ancak EAV masa tasarımı için iyi bir alternatif olarak kullanılabilir.

Umarım birine yardım eder.


1
Bu tasarımın kompozit indekslerle orijinal tasarımınızdan daha iyi performans göstermesi pek olası değildir. Bunları karşılaştırmak için hangi testleri yaptınız?
ypercubeᵀᴹ

0

Uygun görünen sorgu dizini ipuçlarını kullanmayı deneyin

MySQL Dizin İpuçları


1
İpuçları, sorgunun bir sürümüne yardımcı olabilir, ancak başka bir kişiye zarar verebilir. Optimize Edici'nin bornyear'ı en iyi ilk tablo olarak seçtiğini unutmayın.
Rick James
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.