MySQL arama işlemini optimize

4 Cevap php

İşte scenario 1. olduğunu

I have a table called "items", inside the table has 2 columns, e. g. item_id and item_name. I store my data in this way: item_id | item_name

Ss001   | Shirt1
Sb002   | Shirt2
Tb001   | TShirt1
Tm002   | TShirt2

... etc, i store in this way: first letter is the code for clothes, i.e S for shirt, T for tshirt second letter is size, i.e s for small, m for medium and b for big Lets say in my items table i got 10,000 items. I want to do fast retrieve, lets say I want to find a particular shirt, can I use:

Yöntemi1:

SELECT * from items WHERE item_id LIKE Sb99;

ya da ben gibi yapmanız gerekir:

Method2:

SELECT * from items WHERE item_id LIKE S*;

*Store the result, then execute second search for the size, then third search for the id. Like the hash table concept. What I want to achieve is, instead of search all the data, I want to minimize the search by search the clothes code first, follow by size code and then id code. Which one is better in term of speed in mysql. And which one is better in long run. I want to reduce the traffic and not to disturb the database so often.

Teşekkür benim ilk senaryo çözümü için çocuklar. Ama başka bir senaryo geliyor:

Scenario 2:

PHP ve MySQL kullanıyorum. Preivous hikaye devam ediyor. Benim kullanıcıların tablo yapısı bu gibi ise:

user_id | username | items_collected

U0001   | Alex     | Ss001;Tm002
U0002   | Daniel   | Tb001;Sb002
U0003   | Michael  | ...
U0004   | Thomas   | ...

Ben (biz 1000 varsa hayal veritabanı alanlarda çok büyük miktarda gerekli olur, ben dize olarak saklamak eğer bir gün her kullanıcı, yüzlerce öğeleri toplayabilirsiniz çünkü id şeklinde items_collected, yani Shirt1, pants2, saklayabilirsiniz ... kullanıcıların ve bazı öğeler adı) çok uzun.

Ben id şeklinde depolamak eğer korumak daha kolay olurdu?

Ve ben görüntüyü görüntülemek istediğiniz, ve resmin ismi ürün ismi + jpg olduğunu söylemek sağlar eğer. Bunu nasıl? Bu gibi bir şeydir:

$ Result = Seç userid = $ Userid kullanıcılarından items_collected

Kullanımı php patlayabilir:

$ ItemsCollected = explode ($ sonuç ";");

Bundan sonra, ürün tablosundaki her öğeyi eşleştirerek, bu yüzden istiyorum:

shirt1, pants2 vb

Görüntüyü göstermek için döngü fonksiyonu, döngü her bir değeri kullanarak Den ve ekleme ". Jpg"?

4 Cevap

İlk yöntem daha hızlı olacak - ama IMO bunu yapmanın doğru yolu bu değil. Ben bu konuda tehvan ile anlaşma değilim.

Ben o zaman yapabileceğiniz, olduğu gibi item_id tutulması tavsiye, ama fazladan iki tarlalar kodu için bir ve boyutu için bir tane eklemek istiyorum:

select * from items where item_code = 'S' and item_size = 'm'

Indeksleri ile performansı büyük ölçüde artmış olacak ve kolayca boyutlarda, veya kodları bir dizi maç mümkün olacak.

select * from items where item_code = 'S' and item_size IN ('m','s')

Aşağıdaki gibi db geçirme:

alter table items add column item_code varchar(1) default '';
alter table items add column item_size varchar(1) default '';

update items set item_code = SUBSTRING(item_id, 1, 1);
update items set item_size = SUBSTRING(item_id, 2, 1);

Kod değişiklikleri eklemek için aynı derecede basit olmalıdır. Uzun vadeli yarar çabaya değer olacaktır.


Senaryo 2 - bir veritabanından veri almak ve saklamak etkin bir yol değildir. Bu şekilde kullanıldığında, veritabanı yalnızca alanlarına birden fazla veri kodlama yararlı olmaktan veritabanının ilişkisel kısmını engelleyen olan tarafından bir depolama motoru olarak davranmaktadır.

Ne bu durumda yapmanız gereken, başka bir tablo var 'items_collected' çağırmaktır. Şema çizgisinde olurdu

CREATE TABLE items_collected (
   id int(11) NOT NULL auto_increment KEY,
   userid int(11) NOT NULL,
   item_code varchar(10) NOT NULL,  
   FOREIGN KEY (`userid`) REFERENCES `user`(`id`),
   FOREIGN KEY (`itemcode`) REFERENCES `items`(`item_code`)
 );

Yabancı anahtarları Referential integrity, bu to have referential integrity önemlidir olduğundan emin olun.

Sonra örneğin birden fazla kayıt olurdu verir.

 user_id | username | items_collected
 U0001   | Alex     | Ss001
 U0001   | Alex     | Tm002
 U0002   | Daniel   | Sb002
 U0002   | Daniel   | Tb001
 U0003   | Michael  | ...
 U0004   | Thomas   | ...

Sonuçlar için hızlandırmak istiyorsanız, birden fazla sütun halinde her özellik için bir sütun ayrılmalıyız.

Adım 2, her sütun için bir dizin oluşturmak için. Mysql sadece sorgu başına masanın başına bir dizin kullanan unutmayın. Eğer gerçekten hızlı sorguları istiyorum ve sorgular bu özellikleri ile bir çok değişir Yani, o vb (türü, boyutu, biten), (türü, biten, boyut) üzerinde bir dizin oluşturmak isteyebilirsiniz

Örneğin bir sorgu

select * from items where type = s and size = s and ending = 001

Endeksi (türü, boyutu, biten) ama yararlanabilir:

select * from items where  size = s and ending = 001

Indeksi sadece sırayla kullanılacak, o halde biten, türünü, daha sonra büyüklük gerektiğinden, yapamam. Eğer gerçekten hızlı arama isterseniz çoklu indeksler isteyebilirsiniz nedeni budur.

Bir diğer not, genellikle sorgularda * kullanmak, ancak sadece ihtiyacınız olan sütunları seçmek için iyi bir fikir değildir.

Sen model, size ve id, ve indeksi onlara bu şekilde üç sütun olması gerekir:

CREATE INDEX ix_1 ON (model, size, id)
CREATE INDEX ix_2 ON (size, id)
CREATE INDEX ix_3 ON (id, model)

Sonra parametrelerden herhangi bir alt üzerinde verimli aramak mümkün olacak:

  • model-size-id, model-size ve model sorguları kullanır ix_1;
  • size-id ve size sorguları kullanır ix_2;
  • model-id ve id sorguları kullanır ix_3

Şimdi olduğu gibi sütun üzerinde Endeksi ix_1 eşdeğerdir, ve {verimli (model-size-id, model-size, uygun koşulları aramak için bu dizini kullanabilir ve [(3)]}).

Aslında, INDEX SKIN SCAN bir bileşik endeksi olmayan ilk sütunlarda aramak için kullanılan olabilir, ama MySQL AFAIK bunu desteklemiyor denilen belli bir erişim yolu vardır.


Eğer mevcut tasarımına sadık gerekiyorsa, dizine gibi alan ve kullanımı sorgularını gerekir:

WHERE item_id LIKE @model || '%'
WHERE item_id LIKE @model || @size || '%'
WHERE item_id = @model || @size || @id

Varsa Tüm bu sorgular indeksi kullanır.

Birden fazla sorgu içine koymak gerek yoktu.

Sana testi bir "ile başlar" ile aranabilir olmak için item_id tasarlanmış ettik rahatım. Indeksleri sizin için hızlı bir şekilde çözecektir.

Içerdiği değerler çünkü MySQL bilmiyorum, ama MSSQL sadece S seçimler bir "Boyut" sütununda bir dizin sahip, M, L muhtemelen hiçbir şey elde edemezsiniz, endeks kullanılmıştır olmayacak yeterince seçici değil - onun daha hızlı, yani sadece tüm verileri üzerinden gitmek ziyade "endeksinde ilk S girdiyi bulun, şimdi bu satır için veri sayfasını almak ..."

Sorgu endeksi ile kaplı olduğu istisna - fıkra (ve aslında, hepsi ve aynı zamanda SEÇ sütunlar) endekse dahil NEREDE çeşitli yerlerinde yani. Bu durumda, bununla birlikte, (MSSQL) endekste ilk alan seçici olması gerekir. Yani endeksinde ilk en farklı değerlere sahip sütun koydu.

Uygulama Boyutu bir seçim listesinden varsa, Renk, vb kayıtlarında ayrı sütunlarda nitelikleri bu verileri olması gerektiğini söyledikten sonra - ve tüm mevcut Renkler ve Boyutları, ve listeleri ile ayrı tablolar daha sonra doğrulamak anlamına Renk Bir Ürüne verilen / Boyut aslında Renkli / Boyut tabloları tanımlanmıştır. Çöp-in / Çöp Çıkış sorun aşağı keser!

İşletme item_selected it "normaldir" ve böylece ayrı bir tabloda olması gerekir. Tek bir sütunda bir ayrılmış bir listesini tutmayın, ayrı bir tabloya tek tek satırları kullanarak saklayın

Böylece KULLANICILARI masa user_id & içerecektir kullanıcı adı

Sizin, yeni, items_collected masa irade User_id & içeriyor item_id (ve muhtemelen de tarihi Satın alınan ya da Fatura Numarası)

Daha sonra "Alex ne aldın" diyebilirim (tasarım olduğunu) ve aynı zamanda (sizin tasarım, sizin KULLANICILARI masa ve bölme dışında tüm satırlar aracılığıyla çiftçilik gerektirecek, "Kim SS001 aldım" hangi olanları bulmak items_collected içerdi SS001 [1])

Eğer LIKE '% SS001%' items_collected NEREDE maç olur "Ss001XXX" bir item_id olabilir çünkü [1] GİBİ kullanarak gerçekten bunun için güvenli olmaz unutmayın