MySQL neden MyISAM veya InnoDB'de karma endekslere sahip değil?


35

Sadece eşitliği seçecek bir uygulamam var ve btree endeksi üzerinde karma endeksi kullanmam gerektiğini düşünüyorum. Benim dezavantajım için, hash endeksleri MyISAM veya InnoDB'de desteklenmiyor. Bunun nesi var?


2
Mysql ayrıca işlev tabanlı dizinleri, bitmap dizinlerini vb.

1
Ben sadece hash endekslerinin çok ... temel olduğunu düşündüm ... özel bir uygulama sebebi olduğunu varsayıyorum.

1
@Alex: Bu nedenin "tembellik" ve "bürokrasi" olduğunu iddia ediyorum ama cevapları bekleyelim))


High Performance MySQL Book'tan cevabımın sonuna kadar güzel bir HASH algoritması ekledim.
RolandoMySQLDBA

Yanıtlar:


16

Birçok veritabanları karma bazlı endeksler desteklemeyen hiç .

Bir karma tablosunun verimli olması için, mevcut olması muhtemel olan satır sayısını bilmeniz gerekir, aksi takdirde temel karma tablosu çok büyük (çok fazla boş giriş, boşa harcanan ve potansiyel olarak disk GÇ) veya çok küçük olacaktır dolaylı kullanım çoğu zaman kullanılır (muhtemelen birden fazla dolaylı seviye veya karma uygulama tek seviyeli ise daha da kötüsü, bir noktada ağaç temelli bir ağaçtan daha verimli olmayan bir noktada, çok sayıda kayıt üzerinde doğrusal bir arama yaparak sonuçlanabilir) Yine de indeksleyin.

Bu nedenle, genellikle yararlı olması için (yani genellikle alternatiften daha iyi), önemli ölçüde aralıklı bir ek yük ekleyebilecek veri büyüdükçe (ve daraştıkça) endeksin zaman zaman yeniden oluşturulması gerekir. Yeniden oluşturma muhtemelen oldukça hızlı olacağından (veriler her zaman RAM’de olacağından ve her durumda büyük olasılıkla büyük olasılıkla olmadığından) bu genellikle bellek tabanlı tablolarda iyidir, ancak diskte büyük bir dizin oluşturmak çok ağır bir işlem (ve IIRC mySQL canlı indeks yeniden oluşturmalarını desteklemez, bu nedenle işlem sırasında bir masa kilidi tutar).

Bu nedenle, karma dizinler genellikle daha iyi performans gösterdikleri için bellek tablolarında kullanılır, ancak disk tabanlı tablolar, bonus değil performansa zarar verebileceği için bunları desteklemez. Elbette, disk tabanlı tablolar için kullanılabilir yapılıyor durdurma karma endeksler bir şey yok, hiçbir bazı veritabanları şüphe yapmak özelliği desteklemesi, ancak muhtemelen onlar ISAM uygulanmadı / maintainers'ı olarak InnoDB tablolar olarak özellik değerinde ekleme (düşünmüyoruz yazması ve sürdürmesi için ekstra kod, önemli bir fark yarattığı bu birkaç durumda faydaya değmez). Belki de kesinlikle katılmıyorsanız, onlarla konuşabilir ve özelliğin uygulanması için iyi bir dava açabilirsiniz.

Büyük dizeleri dizine ekliyorsanız, kendi sözde-karma dizinini uygularsanız (gerçek değerin yanı sıra, değerin bir karma değerini depolayarak da sütun içeren indeksleme) çalışabilir, ancak bu yalnızca büyük dizeler için daha verimlidir (burada karma değerinin hesaplanması ve ağaç endeksinin bu değer ile aranması her zaman daha hızlı olacaktır, daha sonra sadece karşılaştırma için daha büyük değerleri kullanarak bir ağaç endeksinin aranması ve kullanılan fazladan depolama alanı önemli olmayacaktır). bu üretimde.


Tüm masanın kilitlenmeden yan yana yapılmasının (yeniden yapılanmanın) yan yana yapılmasına izin vermenin bir yolu var mı?
Pacerier

@Pacerier: MySQL ile bilmediğim bir şey değil (en son kullandığımdan beri özelliği ekleselerdi, bu yüzden belgeleri kontrol et). Bir DBMS'nin çevrimiçi dizin oluşturmayı / yeniden oluşturmayı desteklediği yerlerde bile, varsayılan seçenek değildir. Kilitli olanlar değişecektir: bazıları masaya yazma kilidini tutacaktır, diğer işlemler yalnızca gecikmeli ise gecikmez, bazı DMBS'ler tam masa kilidini alır. Çevrimiçi yeniden oluşturmaya ihtiyacınız varsa , hangisini kullanacağınızı seçmeden önce her DBMS'nin belgelerine bakın.
David Spillett

Genellikle yeniden oluşturma, yalnızca veri uzunluğu iki katına çıkarıldığında gerekir. Veri uzunluğunun her dakika iki katına çıkması konusunda gerçekten endişelenmeleri gerekiyor mu? (normalde, veritabanı bunun bir endişe kaynağı olacak kadar büyüyünce çok nadir
görülür

6

İlgili bir notta, PostgreSQL dokümanlarından ilgi çekici endeks türleriyle ilgili tartışmaları bulabilirsiniz. Artık dokümanın son sürümlerinde mevcut değil (sonraki optimizasyonlar nedeniyle, bunu alıyorum), ancak paket servisi MySQL için benzer olabilir (ve karma dizinlerinin yalnızca yığın tabloları için kullanılmasının nedeni):

http://www.postgresql.org/docs/8.1/static/indexes-types.html

Not: Test Etme, PostgreSQL'in karma dizinlerini B ağacı dizinlerinden daha iyi performans göstermediğini gösterdi ve karma dizinler için dizin boyutu ve oluşturma süresi çok daha kötü. Ayrıca, karma dizin işlemleri şu anda WAL günlüğünde değildir, bu nedenle bir veritabanı çökmesinden sonra karma dizinlerin REINDEX ile yeniden oluşturulması gerekebilir. Bu nedenlerden dolayı, hash endeksi kullanımı halen önerilmemektedir. Benzer şekilde, R-ağacı endeksleri, GiST endekslerinin eşdeğer işlemlerine kıyasla hiçbir performans avantajına sahip görünmemektedir. Karma dizinler gibi, WAL günlüğüne kaydedilmemişlerdir ve bir veritabanı çökmesinden sonra yeniden indekslemeye ihtiyaç duyabilirler. Sonunda karma dizinleri ile ilgili sorunlar çözülebilse de, R-ağacı dizin türünün gelecekteki bir sürümde emekli olması muhtemeldir. Kullanıcılar, R-ağacı dizinlerini kullanan uygulamaları GiST dizinlerine geçirmeye teşvik edilir.

Yine, PostgreSQL'e özgü (eski sürüm), ancak "doğal" dizin türünün mutlaka en iyi performansı vermeyeceğini ima etmesi gerekir.


5

İşte ilginç bir şey:

Kitaba göre 5.0 Sertifikasyon Eğitim Kılavuzu MySQL , Sayfa 433, Bölüm 29.5.1

MEMORY motoru, varsayılan indeksleme algoritması tarafından HASH kullanır.

Gülmek için, MySQL 5.5.12’de HASH kullanarak bir InnoDB tablosu ve bir birincil anahtarla bir MyISAM tablosu oluşturmaya çalıştım.

mysql> use test
Database changed
mysql> create table rolando (num int not null, primary key (num) using hash);
Query OK, 0 rows affected (0.11 sec)

mysql> show create table rolando\G
*************************** 1. row ***************************
       Table: rolando
Create Table: CREATE TABLE `rolando` (
  `num` int(11) NOT NULL,
  PRIMARY KEY (`num`) USING HASH
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> create table rolando2 (num int not null, primary key (num) using hash) engine=MyISAM;
Query OK, 0 rows affected (0.05 sec)

mysql> show create table rolando2\G
*************************** 1. row ***************************
       Table: rolando2
Create Table: CREATE TABLE `rolando2` (
  `num` int(11) NOT NULL,
  PRIMARY KEY (`num`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

MySQL şikayet etmedi.

GÜNCELLEME

Kötü haber !!! SHOW INDEXES FROM kullandım. Endeksin BTREE olduğunu söylüyor.

Index sözdizimi MySQL Sayfa CREATE tek BELLEK ve NDB depolama motorları HASH INDEX ağırlayacak belirtiyor.

mysql> show indexes from rolando;
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table   | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| rolando |          0 | PRIMARY  |            1 | num         | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

mysql> show indexes from rolando2;
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table    | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| rolando2 |          0 | PRIMARY  |            1 | num         | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

mysql> create table rolando3 (num int not null, primary key (num)) ENGINE=MEMORY;
Query OK, 0 rows affected (0.03 sec)

mysql> show create table rolando3\G
*************************** 1. row ***************************
       Table: rolando3
Create Table: CREATE TABLE `rolando3` (
  `num` int(11) NOT NULL,
  PRIMARY KEY (`num`)
) ENGINE=MEMORY DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> show indexes from rolando3;
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table    | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| rolando3 |          0 | PRIMARY  |            1 | num         | NULL      |           0 |     NULL | NULL   |      | HASH       |         |               |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

Bazı insanlar , hash algoritmasını taklit etmek için " Yüksek Performanslı MySQL: Optimizasyonlar, Yedeklemeler, Çoğaltma ve Daha Fazlası " kitabının 102-105. Sayfalarındaki fikrini izlemeyi önerdi .

Page 105 beğendiğim bu hızlı ve kirli algoritmaya sahip:

SELECT CONV(RIGHT(MD5('whatever value you want'),16),16,10) AS HASH64;

Herhangi bir tabloda bunun için bir sütun yapın ve bu değeri indeksleyin.

Bir şans ver !!!


5
Üretimde sözde hash-index tekniğini kullanmadan önce üzerinde bazı performans analizleri yapın. Büyük dizeleri için bu büyük bir fark yaratabilir ama yine de sonuçta bir ağaç indeksini navigasyona sonunda, ve ekstra kadar küçük karma değerlerini hesaplamak değerler ve için, karma eşleşen bulunanlara doğru satır bulmak için yapmak karşılaştırır var Onları saklamak buna değmez. Bu gerçekten bir karma endeksi değildir, sadece ağacın yürüdüğü işi azaltırsınız.
David Spillett

@David Spillett Bu konuda tamamen size katılıyorum. Diğer endeksleme zorlukları da aynı kitapta Bölüm 11 "Yüksek Performans için Endeksleme Stratejileri" bölümünde önerilmektedir. Cevabımı ek olarak, kitap aslında aynı yapıdaki satırı ve BTree Endeksini depolayan kümelenmiş bir indeks kullanmaktan bahsediyor. Bu, bahsettiğiniz azalmış işi hızlandırmak olabilir. Ne yazık ki, az önce bahsettiğinizden atlamanız gereken çemberler kaçınılmazdır. Yine de yorumlarınıza benden bir +1, efendim !!! Aslında, cevabınız için de +1.
RolandoMySQLDBA

@RolandoMySQLDBA "Özel hash" konusunda daha fazla ayrıntı verir misiniz, son paragraf fazla ipucu vermiyor gibi görünüyor ...
Pacerier

2

BTree, tek sıralı arama için Hash'den çok daha yavaş değildir. BTree çok verimli bir dizi sorgulama sağladığından, neden BTree'den başka bir şeyle uğraşmıyorsunuz?

MySQL, BTree bloklarını önbelleğe almak için çok iyi bir iş çıkarır, bu nedenle BTree tabanlı bir sorgu nadiren herhangi bir sorguda en büyük zaman tüketicisi olan G / Ç yapmak zorunda kalır.

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.