Oracle, uzun bir anahtar için benzersiz bir dizin kullanmıyor


16

Test veritabanımda 250K satır içeren bir tablo var. (Üretimde birkaç yüz milyon var, aynı sorunu orada gözlemleyebiliriz.) Tabloda nullchar2 (50) dize tanımlayıcısı var, boş değil, üzerinde benzersiz bir dizin var (PK değil).

Tanımlayıcılar, test veritabanımda (ve üretimde yaklaşık bin) 8 farklı değere sahip bir ilk bölümden, sonra bir @ işaretinden ve son olarak da 1 ila 6 basamak uzunluğunda bir sayıdan oluşur. Örneğin, 'ABCD_BGX1741F_2006_13_20110808.xml @' ile başlayan 50 bin satır olabilir ve bunu 50 bin farklı sayı izler.

Tanımlayıcısına bağlı olarak tek bir satırı sorguladığımda, kardinalite 1 olarak tahmin ediliyor, maliyet çok düşük, iyi çalışıyor. Bir IN ifadesinde veya OR ifadesinde birden fazla tanımlayıcı içeren birden fazla satırı sorguladığımda, dizin için tahminler tamamen yanlış, bu nedenle tam tablo taraması kullanılıyor. Dizini bir ipucu ile zorlarsam, çok hızlıdır, tam tablo taraması aslında daha yavaş bir büyüklükte (ve üretimde çok daha yavaş) gerçekleştirilir. Bu yüzden bir optimizer problemidir.

Bir test olarak, aynı DDL ve tam olarak aynı içeriğe sahip tabloyu (aynı şema + tablo alanında) çoğalttım. İyi ölçmek için ilk tablodaki benzersiz dizini yeniden oluşturdum ve aynı dizini klon tablosunda oluşturdum. Ben yaptım DBMS_STATS.GATHER_SCHEMA_STATS('schemaname',estimate_percent=>100,cascade=>true);. Hatta dizin adlarının ardışık olduğunu görebilirsiniz. Bu yüzden şimdi iki tablo arasındaki tek fark, birincinin uzun bir süre boyunca rastgele sırada yüklenmesi, blokların diske dağılmış olması (diğer birkaç büyük tablo ile birlikte bir tablo alanında), ikincisinin toplu olarak yüklenmesi INSERT- SEÇ. Bunun dışında hiçbir fark düşünemiyorum. (Orijinal tablo son büyük silme işleminden bu yana küçüldü ve bundan sonra tek bir silme olmadı.)

İşte hasta ve klon tablosu için sorgu planları (Siyah fırçanın altındaki teller resmin her tarafında ve gri fırçanın altında aynıdır.):

sorgu planları

(Bu örnekte, siyah fırçalanmış tanımlayıcıyla başlayan 1867 satır vardır. 2 satırlı sorgu 1867 * 2 kardinalitesi, 3 satırlı sorgu 1867 * 3 kardinalitesi üretir, vb. tesadüf olarak, Oracle tanımlayıcıların sonunu umursamıyor gibi görünüyor.)

Bu davranışa ne sebep olabilir? Tabii üretimde tabloyu yeniden oluşturmak oldukça pahalı olurdu.

USER_TABLES: http://i.stack.imgur.com/nDWze.jpg USER_INDEXES: http://i.stack.imgur.com/DG9um.jpg Yalnızca şema ve tablo alanı adını değiştirdim. Tablo ve dizin adlarının sorgu planı ekran görüntüsüyle aynı olduğunu görebilirsiniz.

Yanıtlar:


7

(Bu , histogramların neden farklı olduğu hakkındaki diğer soruyu cevaplar .)

Histogramlar, varsayılan olarak sütun eğimine ve sütunun ilgili yüklemde kullanılıp kullanılmadığına göre oluşturulur . DDL ve verilerin kopyalanması yeterli değildir, iş yükü bilgileri de önemlidir.

Göre Performans Ayarlama Rehberi :

Bir tabloyu bıraktığınızda, otomatik histogram toplama özelliği tarafından kullanılan iş yükü bilgileri ve RESTORE _ * _ STATS yordamları tarafından kullanılan kaydedilmiş istatistik geçmişi kaybolur. Bu veriler olmadan, bu özellikler düzgün çalışmaz.

Örneğin, eğri verileri olan ancak histogramı olmayan bir tablo:

drop table test1;
create table test1(a date);
insert into test1 select date '2000-01-01'+level from dual connect by level <= 10;
insert into test1 select date '2000-01-01' from dual connect by level <= 1000;
begin
    dbms_stats.gather_table_stats(user, 'TEST1');
end;
/
select histogram from user_tab_columns where table_name = 'TEST1';

HISTOGRAM
---------
NONE

Aynı şeyi çalıştırmak, ancak istatistikler toplanmadan önce bir sorgu ile bir histogram oluşturur.

drop table test1;
create table test1(a date);
insert into test1 select date '2000-01-01'+level from dual connect by level <= 10;
insert into test1 select date '2000-01-01' from dual connect by level <= 1000;
select count(*) from test1 where a = sysdate; --Only new line
begin
    dbms_stats.gather_table_stats(user, 'TEST1');
end;
/
select histogram from user_tab_columns where table_name = 'TEST1';

HISTOGRAM
---------
FREQUENCY

2
Zekice basit bir örnek. CBO'nun neden sadece 1 varsaymak yerine benzersiz bir taramada kardinalite tahminleri için histogramlar kullandığına dair bir fikriniz var mı?
Jack diyor ki topanswers.xyz

Teşekkürler! Blogumdaki veri ve sorgularım ile tam bir repro yaptım: joco.name/2014/01/05/…
fejesjoco

@Jack bence tembellik. Oracle mühendisleri, benzersiz bir dizinin istatistiklerinin satırlarla aynı sayıda farklı değere sahip olacağını bulmalıydı, bu nedenle 1 kardinalite varsayımı kablo bağlantılı değil, diğer durumlarda olduğu gibi istatistiklerden sadece kullanıldı. Ayrıca, genel bir durum olarak, histogramlar basit istatistikleri koyar. Benim durumum sadece uzun tuşlar nedeniyle çok özel görünüyor, ama bunun aksi takdirde oldukça iyi çalıştığına inanıyorum.
fejesjoco

@fejesjoco Bence JL'nin açıklaması daha olasıdır, çünkü histogramlar da tek bir arama durumunda genel istatistikleri gölgede inbırakacaktı, öyle değil mi? CBO'nun kardinalite 1 varsayımı yaptığını düşünüyorum, ancak sadece en basit durumda. Her şeyi büyük bir kullanarak çalıştırabileceğinizi varsayıyorum, UNION ALLancak bunu yapmamak için başka nedenler olabilir ve JL, bağlantılı blog yayınında olası diğer geçici çözümlerden bahseder.
Jack diyor ki topanswers.xyz

1
Dikkate alınması gereken bir diğer küçük gizem - bu histogram ilk etapta nasıl oluşturuldu? Oracle, yalnızca benzersiz sütununuzun sahip olamayacağı yinelenen sütunları çarpık olarak kabul ediyor gibi görünüyor. Birisi bu histogramı kasıtlı olarak oluşturdu (olası değil) veya biri önerilmeyenlerle istatistik topladı method_opt=>'for all indexed columns'mı?
Jon Heller

8

Çözümü buldum! Çok güzel ve aslında Oracle hakkında çok şey öğrendim.

Tek kelimeyle: histogramlar.

Oracle'ın CBO'sunun nasıl çalıştığı hakkında çok şey okumaya başladım ve histogramlara tökezledim. Tam olarak anlamadım, bu yüzden USER_HISTOGRAMS tablosuna ve voilá'ya baktım. Hasta masası için birkaç satır vardı ve klonlanmış tablo için neredeyse hiçbir şey yoktu. Hasta tablosu için 8 farklı tanımlayıcı başlangıç ​​parçasının her biri için bir sıra vardı. Ve bu anahtar: @ işaretinden önce 32 karakterden kesildi. Dediğim gibi, tuşların ilk kısmı oldukça tekrarlı, @ işaretinden sonra farklılaşıyorlar.

Histogramların, benzersiz bir endeksin belirli bir değer için her zaman 0 veya 1'lik bir kardinaliteye sahip olduğu basit gerçeğinden daha güçlü olabileceği görülmektedir. 2+ satır için sorgulama yaparken, Oracle histograma baktı, bu tanımlayıcı başlangıç ​​kısmı için on binlerce değer olabileceğini düşündü ve CBO'yu elbette attı.

Eski tablodaki sütun için histogramları sildim ve sorun ortadan kalktı!

Daha fazla okuma: https://blogs.oracle.com/optimizer/entry/how_do_i_drop_an_existing_histogram_on_a_column_and_stop_the_auto_stats_gathering_job_from_creating


2
Sohbet odamızda bunu
söylemiştim

Bunu görmedim :). Bu yüzden tek garip şey neden ilk tabloda ve klonda histogramların olmamasıydı, görünüşe göre değil, her şeyi güncellediğini düşündüm.
fejesjoco

6

Bu konuda Jonathan Lewis'e e-posta gönderdim ve çok yardımcı bir cevap aldım:

Hesaplamadaki tuhaflık, karakter tabanlı histogramlar üzerindeki sınırların bir sonucudur, özellikle bakınız:

http://jonathanlewis.wordpress.com/2010/10/13/frekans-histogram-5/ http://jonathanlewis.wordpress.com/2010/10/19/frekans-histogramlar-6/

Örneğe bakıldığında, sorgu tek bir satır için değil, bir IN listesi içindir, bu nedenle ilk tahminim, optimize edicinin bir satır için özel bir kod parçasına sahip olmak yerine çok satırlı seçiciliği hesaplamak için genel bir strateji kullanmasıdır. Birincil anahtarda IN listesi. Sanırım bu davayı tanımak çok zor olmayacaktı, ancak geliştiriciler muhtemelen çabaya değeceğini düşünmemişlerdi.

Bağladığı blog yayınlarını okumanızı şiddetle tavsiye ettim, ayrıntılı olarak çalıştığınız histogramların sınırlamasını ayrıntılı olarak açıklarlar, örneğin:

Sonuç : Bir frekans histogramı için iyi bir aday olan bir sütunda (örneğin, çok açıklayıcı bir durum sütunu) oldukça uzun ve benzer dizeleriniz varsa, çok nadir olan bir değer çok popüler ile aynı görünüyorsa bir sorununuz var demektir. değeri ilk 32 karaktere kadar. Tek çözümün yasal değerler listesini değiştirmek olduğunu görebilirsiniz (sanal sütunları veya işlev tabanlı dizinleri içeren çeşitli stratejiler sorunu atlayabilir).


Ne yazık ki histogramlar biraz bilinen bir özellik gibi görünüyor, çünkü bir SQL geliştiricisi için çok derin ve çoğu zaman sadece çalışıyorlar, ancak bunun hakkında birçok kaynak olduğunu bilmek güzel, sadece bakmıyordum doğru yerler :). Oracle'ın 32 baytta kesmesi ve buna bağlı olarak feci kararlar alması oldukça kötü. Neyse ki, herhangi bir ayarlamaya ihtiyacım yok, histogramları bırakmak mükemmel bir çözüm. Anahtar değerler benzersizdir, her zaman bir seferde 20 değer ararım, sadece bir dizinle iyi çalışır ve deterministiktir. Ama bir dahaki sefere uzun anahtar kullanmayacağım, bu kesin.
fejesjoco

Histogramlar DBA'lar arasında oldukça iyi bilinir;) Daha derin şeyler öğrenmeye hevesli olduğunuzu ve JL'nin kitabını okumalısınız gerçekten çok iyi olduğunu düşünüyorum. CBO genellikle harika bir iş çıkarır: her zaman araştırılması gereken son durumlar olacaktır, ancak kesilmeden bile tahminlerin her zaman sadece tahminler olduğunu akılda tutmaya değer.
Jack diyor ki topanswers.xyz

1
Düzenli bir istatistik işi çalıştırırsanız ( Oracle'ın temiz bir yüklemede varsayılan olarak çalıştığı gibi ), histogramların yeniden ortaya çıktığını görebilirsiniz, bunu önlemenin bir yolunu aramanız gerekebilir ( belki LOCK_TABLE_STATS gibi )
Jack, topanswers'ı deneyin. xyz

Cevabımda bir blog gönderisinden bahsetmiştim, bir sütun için histogramların nasıl önleneceğine dair talimatlar var.
fejesjoco

1
Jack Douglas, J. Lewis'i dahil ettiğiniz ve geri bildirimde bulunduğunuz için teşekkür ederiz!
Dimitre Radoulov
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.