MySQL'de koşullu bir dizin nasıl oluşturulur?


24

MySQL'de tablonun belirli bir aralığını veya alt kümesini filtrelemek için bir dizin nasıl oluşturulur? AFAIK doğrudan oluşturmak imkansız ama bence bu özelliği simüle etmek mümkün.

Örnek: NAMEYalnızca satır içeren sütunlar için bir dizin oluşturmak istiyorum.STATUS = 'ACTIVE'

Bu işlevsellik , SQL Server'da filtrelenmiş bir dizin ve Postgres'te kısmi bir dizin olarak adlandırılır .

Yanıtlar:


9

MySQL şu anda koşullu dizinleri desteklememektedir.

Ne istediğinizi anlamak için (yapmamalısın;);) bir yardımcı tablo oluşturmaya başlayabilirsiniz:

CREATE TABLE  `my_schema`.`auxiliary_table` (
   `id` int unsigned NOT NULL,
   `name` varchar(250), /* specify the same way as in your main table */
   PRIMARY KEY (`id`),
   KEY `name` (`name`)
);

Sonra ana tabloya üç tetikleyici eklersiniz:

delimiter //

CREATE TRIGGER example_insert AFTER INSERT ON main_table
FOR EACH ROW
BEGIN
   IF NEW.status = 'ACTIVE' THEN
      REPLACE auxiliary_table SET
         auxiliary_table.id = NEW.id,
         auxiliary_table.name = NEW.name;
   END IF;
END;//

CREATE TRIGGER example_update AFTER UPDATE ON main_table
FOR EACH ROW
BEGIN
   IF NEW.status = 'ACTIVE' THEN
      REPLACE auxiliary_table SET
         auxiliary_table.id = NEW.id,
         auxiliary_table.name = NEW.name;
   ELSE
      DELETE FROM auxiliary_table WHERE auxiliary_table.id = OLD.id;
   END IF;
END;//

CREATE TRIGGER example_delete AFTER DELETE ON main_table
FOR EACH ROW
BEGIN
   DELETE FROM auxiliary_table WHERE auxiliary_table.id = OLD.id;
END;//

delimiter ;

İhtiyacımız var delimiter //çünkü ;tetikleyicilerin içinde kullanmak istiyoruz .

Bu şekilde, yardımcı tablo tam olarak tetikleyiciler tarafından güncellenen "ACTIVE" dizisini içeren ana tablo satırlarına karşılık gelen ID'leri içerecektir.

Bunu kullanmak selectiçin normali kullanabilirsiniz join:

SELECT main_table.* FROM auxiliary_table LEFT JOIN main_table
   ON auxiliary_table.id = main_table.id
   ORDER BY auxiliary_table.name;

Ana tablo zaten veri içeriyorsa veya alışılmadık şekilde değiştiren bazı harici işlemler yapmanız durumunda (EG: MySQL dışında), yardımcı tabloyu şununla düzeltebilirsiniz:

INSERT INTO auxiliary_table SET
   id = main_table.id,
   name = main_table.name,
   WHERE main_table.status="ACTIVE";

Performans hakkında muhtemelen daha yavaş ekler, güncellemeler ve silme işlemleriniz olur. Bu, ancak istenen koşulun olumlu olduğu birkaç durumla gerçekten ilgileniyorsanız, bir anlam ifade edebilir. Bu şekilde bile, muhtemelen yalnızca sınanan, alanın bu yaklaşımı haklı gösterip göstermediğini (ve gerçekten de herhangi bir yerden tasarruf ediyorsanız) görebilirsiniz.


7

Eğer ben doğru soruyu anlamadım, ben ne yapmaya çalıştığınız şeyi başarmak istiyorum sütunlar, adı ve durumu hem bir dizin oluşturmak için olduğunu düşünüyorum. Bu verimli bir şekilde NAME = 'SMITH' ve STATUS = 'ACTIVE' sorgularını yapmanıza izin verir


1
Tamam, ancak ACTIVE durumuyla nispeten az sayıda hattınız varsa, bu alan verimli değildir.
Maniero

Hayır, değil, ama bu soruda bir gereklilik değildi ve tablonun değerlerden birine ağır bir şekilde ağırlıklandırıldığı belirtilmedi. Bunun için, aradığın STATUS 'un somutlaştırılmış bir görüntüsünü yaratacağım ama MySQL bunları desteklemiyor.
BlackICE

ve disk alanı ucuz ...
BlackICE 19.04

2
Evet, bu doğrudan bir gereklilik değildir, bu yüzden bir yorum ile bir Tamam ile başladım. Bazı profesyonel alternatifler arıyorum. Ve profesyonel alternatifler her zaman görevlerinizi yerine getirmenin en etkili yolunu arar. Cevabınız muhtemelen en açık olanıdır. Bununla ilgili bir sorun yok. Ancak, "disk alanı ucuz" ile tamamen aynı fikirdeyim, pahalı değil, tabii ki ucuz, ancak bellek o kadar ucuz değil, hafızanın düşük limitleri var ve endeksin verimli olması için öncelikle bellekte yaşaması gerekiyor. Disk erişimi o kadar ucuz değil. Cevabınız kesinlikle hedefe ulaşmak için doğru bir yol ama en iyisi olduğundan şüpheliyim.
Maniero

Ayrıca hafızama katılmıyorum, bugünlerde de oldukça ucuz (disk alanı kadar ucuz değil, ancak bazıları için 10 $ / gig'de biraz
paramparça

6

Koşullu dizin oluşturma işlemini yapamazsınız, ancak örneğin, ( name, status) üzerine çok sütunlu bir dizin ekleyebilirsiniz .

Bu sütunlardaki tüm verileri dizine eklese bile, aradığınız adları "etkin" durumuyla bulmanıza yardımcı olur.


4

Bunu, verileri iki tablo arasında bölerek, tüm veriler gerektiğinde iki tabloyu birleştirmek için görünümleri kullanarak ve bu sütundaki tablolardan yalnızca birini dizine ekleyerek yapabilirsiniz - ancak bunun, gereken sorgularda performans sorunlarına neden olacağını düşünüyorum. sorgu planlayıcısı benim için verdiğimden daha akıllı olmadığı sürece tüm tabloyu çalıştırın. Temel olarak, tabloyu manuel olarak bölümlere ayırıyor olacaksınız (ve dizini bölümlerden yalnızca birine uygulayacaksınız).

Ne yazık ki, yerleşik tablo bölümleme özelliği , tek bir bölüme bir dizin uygulayamayacağınız için görevinizde size yardımcı olmayacaktır.

Dizini olan ek bir sütunu tutabilir ve dizinin temel almasını istediğiniz koşul doğru olduğunda bu sütunda bir değere sahip olabilirsiniz, ancak bu iş yoğunluğu ve kısıtlı (veya negatif) değerinde olabilir. sorgulama verimliliği ve yerden tasarruf.


Sadece daha iyi indeksleme için iki tabloya sahip DEĞİLDİR, çünkü katılım hala pahalı olacak, değil mi?
jcolebrand

@jcolebrand: Genel sorgular için (sendikadaki görüşlere göre) daha pahalı olur, dizini kullanmak için bölüm tablosundan özellikle seçim yapmanız gerekir. Yerleşik bölümleme bunu sizin için verimli bir şekilde yapar, ancak yalnızca belirli dizinleri destekliyorsa Bigown'ın istediği şekilde (yerden tasarruf etmek için). Söylediği olabilir , bunu o isteyeyim değil!
David Spillett

0

MySQL artık dizinler için kullanılabilecek sanal sütunlara sahip.


3
Bu özellik filtrelenmiş bir dizini simüle etmek için nasıl kullanılabilir?
ypercubeᵀᴹ

1
@ yper-trollᵀᴹ, druud62, Oracle’ı düşünüyor olabilir: dbfiddle.uk/… - MySQL NULL’lara aynı şekilde davranmıyor
Jack Douglas

@JackDouglas belki de. (bu arada alandan tasarruf sağlayan bir indeks optimizasyonu değil mi? Başka bir deyişle select count(*) from foo where id is null ;bir indeks kullanabilir mi?)
ypercubeᵀᴹ

@ yper-trollᵀᴹ Oracle, dizine alınmış tüm sütunların NULL olduğu ( use-the-index-luke.com/sql/where-clause/null/index ) - ve sanal bir sütunun bulunduğu satırları dizine eklemezdecode(status,'ACTIVE',name,null) .
Jack Douglas

Thnx, son sürümlerinde değiştiğini düşünmüştüm (ve null indekslendi).
ypercubeᵀᴹ
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.