Mysql join varchar a int, różnice w wydajności?


(pain3hp) #1

Czy w mysqlu joinowanie tabel po kolumnie typowanej na INT jest szybsze od kolumn będących VARCHAR? Oczywiście każda ma założony index.


(Konrad Kosowski) #2

Masz na myśli takie mniej więcej coś:

select a.a,a.b,b.c, from table as a

left join table2 as b on a.d = b.d

I a.d oraz b.d są intami albo varcharami? Wówczas tak.

Jeśli masz jednak na myśli sytuację, gdy typu są rzucane (cast) to wtedy… nie da się castować na int :slight_smile: Da się na signed i unsigned. Ale raczej chodziło Ci o 1… :slight_smile:


(pain3hp) #3

Tak o to mi chodzi, że są typowane na varchar lub int. Co to znaczy “Wówczas tak”. Jeżeli są intami to złączenie będzie szybsze?

Wątpię, aby to miało jakieś znaczenie, masz jakieś uzasadnienie? Z tego co sprawdzałem w necie, to nie ma to kompletnie żadnego znaczenia jeżeli obie są unikalne.

Chyba sobie przeprowadzę jakieś testy na dużych tabelach i opublikuje wynik


(Konrad Kosowski) #4

Na pytanie rodzaju “Czy w mysqlu joinowanie tabel po kolumnie typowanej na INT jest szybsze od kolumn będących VARCHAR?” odpowiedź “Tak” jest niejasna?

Zrobiłem proste doświadczenie. Postawiłem 4 tablice, z trzema kolumnami:

CREATE TABLE `int_raz` (

  `ida` int(11) NOT NULL AUTO_INCREMENT,

  `id` int(11) DEFAULT NULL,

  `asd` varchar(45) DEFAULT NULL,

  PRIMARY KEY (`ida`),

  UNIQUE KEY `id_UNIQUE` (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8$$


CREATE TABLE `int_dwa` (

  `ida` int(11) NOT NULL AUTO_INCREMENT,

  `id` int(11) DEFAULT NULL,

  `asd` varchar(45) DEFAULT NULL,

  PRIMARY KEY (`ida`),

  UNIQUE KEY `id_UNIQUE` (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8$$


CREATE TABLE `v_raz` (

  `ida` int(11) NOT NULL AUTO_INCREMENT,

  `id` varchar(45) DEFAULT NULL,

  `asd` varchar(45) DEFAULT NULL,

  PRIMARY KEY (`ida`),

  UNIQUE KEY `id_UNIQUE` (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8$$


delimiter $$


CREATE TABLE `v_dwa` (

  `ida` int(11) NOT NULL AUTO_INCREMENT,

  `id` varchar(45) DEFAULT NULL,

  `asd` varchar(45) DEFAULT NULL,

  PRIMARY KEY (`ida`),

  UNIQUE KEY `id_UNIQUE` (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8$$

Zapełniłem takimi samymi danymi, 5000 wierszy. I zrobiłem 100 razy joiny. Wyszło mi, że query:

SELECT `v_raz`.`id`, `v_dwa`.`id` FROM (`v_raz`) JOIN `v_dwa` ON `v_raz`.`id` = `v_dwa`.`id`

Wykonuje się 4.2313039302826 sekundy, a query

SELECT `int_raz`.`id`, `int_dwa`.`id` FROM (`int_raz`) JOIN `int_dwa` ON `int_raz`.`id` = `int_dwa`.`id`

wykonuje się 3.7294478416443.

Czyli szybciej.


(kostek135) #5

Uzasadnie to “programistycznie”. Aby coś z czymś “zdżojnować” musisz wiedzieć że wartości pól są takie same (te po których robisz join). No i teraz jak łatwiej stwierdzić, że wartości są takie same? Porównując dwa inty (32 bity), które defaultowo w całości zostaną załadowane do cache’a, czy kilkunastoznakowy (lub nawet kilkudziesięcio) napis. Biorąc pod uwagę, że mysql to szrot wydajnościowy, zapewne algorytm oprogramowujący tę funkcję przebiega znak po znaku w jakiejś pętli for…


(pain3hp) #6

Ok powiedzmy, że VARCHAR jest na 4bajtach (32bity) Czyli tak samo jak INT o którym piszesz. Czy teraz szybkość będzie identyczna? Masz dowód? Jakie to ma znaczenie dla komputera czy ma zapisane “A” czy 1 lub 2 skoro ilość bitów ma taką samą?

Dodane 19.09.2013 (Cz) 19:51

@tfl, zrobiłeś VARCHARY o wielkości 45,więc Twój test jest niesprawiedliwy.

Dodane 19.09.2013 (Cz) 20:14

Dodam jeszcze jedno pytanie czy w MySQLu na silniku InnoDB szybciej realizowane są JOINy jak mamy założone klucze obce? niż jak mamy zwykłe indeksy na kolumnach kluczy obcych?


(kostek135) #7

W MySQL, podejrzewam, że nie. Dopiero przy jednym bajcie powinna być.

Na co bo jakieś pytanie oderwane od kontekstu…

Żadne. Ale joina z reguły robisz na czymś co jest kluczem obcym sensu logicznego - 52 wartości (duże małe litery o pojedynczym wystąpieniu) to raczej nie porywa. Natomiast przy intcie nie ma różnicy czy to jest 1 czy 10^9 a to już robi jakieś tam wrażenie na laiku. Zresztą weź jakąkolwiek sensowną bibliotekę do obliczeń matematycznych. Duże liczby są przechowywane na stringu czy w intowych chunkach?

Dodane 19.09.2013 (Cz) 21:06

Nie wiem czy dobrze zrozumiałem, ale ogólnie głupi pomysł to zakładać indeks na kolumnę kluczy obcych (teoretycznie jeśli nie ma ograniczeń biznesowych wszystkie wartości mogą być takie same). Indeks należy zakładać tam, gdzie wartości są różne. Natomiast na kolumny o małym wachlarzu różnych wartości można zakładać to: http://en.wikipedia.org/wiki/Bitmap_index


(Konrad Kosowski) #8

Nie rozumiem cie nieco… zacząłeś od pytania, potem robisz wszystko, żeby obalić to co ci ludzie odpowiadają.

SELECT `int_raz`.`id`, `int_dwa`.`id` FROM (`int_raz`) JOIN `int_dwa` ON `int_raz`.`id` = `int_dwa`.`id`

2.908313035965

SELECT `v_raz`.`id`, `v_dwa`.`id` FROM (`v_raz`) JOIN `v_dwa` ON `v_raz`.`id` = `v_dwa`.`id`

3.12455701828


SELECT `int_raz`.`id`, `int_dwa`.`id` FROM (`int_raz`) JOIN `int_dwa` ON `int_raz`.`id` = `int_dwa`.`id`

2.7187161445618

SELECT `v_raz`.`id`, `v_dwa`.`id` FROM (`v_raz`) JOIN `v_dwa` ON `v_raz`.`id` = `v_dwa`.`id`

3.1223440170288


SELECT `int_raz`.`id`, `int_dwa`.`id` FROM (`int_raz`) JOIN `int_dwa` ON `int_raz`.`id` = `int_dwa`.`id`

2.7724049091339

SELECT `v_raz`.`id`, `v_dwa`.`id` FROM (`v_raz`) JOIN `v_dwa` ON `v_raz`.`id` = `v_dwa`.`id`

3.1450490951538

Wychodzi, że nawet na varchar(4) wynik mimo wszystko jest na korzyść int.