Sql maswali mengi katika moja. SELECT COUNT nyingi katika hoja moja ya MySQL. Kuboresha Maswali ya MySQL

Katika nakala hii fupi tutazungumza juu ya hifadhidata haswa MySQL, sampuli na kuhesabu. Unapofanya kazi na hifadhidata, mara nyingi unahitaji kuhesabu idadi ya safu COUNT() na au bila hali fulani hii ni rahisi sana kufanya na swali lifuatalo

Angalia msimbo MYSQL

Hoja itarudisha thamani iliyo na idadi ya safu mlalo kwenye jedwali.

Kuhesabu kwa hali

Angalia msimbo MYSQL

Hoja itarudisha thamani iliyo na idadi ya safu mlalo kwenye jedwali zinazokidhi hali hii: var = 1

Ili kupata maadili ya kuhesabu safu nyingi na hali tofauti, unaweza kuendesha maswali kadhaa moja baada ya nyingine, kwa mfano

Angalia msimbo MYSQL

Lakini katika hali nyingine, mbinu hii sio ya vitendo na sio sawa. Kwa hivyo, inakuwa muhimu kupanga swali na hoja ndogo kadhaa ili kupata matokeo kadhaa mara moja katika hoja moja. Kwa mfano

Angalia msimbo MYSQL

Kwa hivyo, kwa kutekeleza swala moja tu kwenye hifadhidata, tunapata matokeo na hesabu ya idadi ya safu kwa hali kadhaa, zilizo na maadili kadhaa ya hesabu, kwa mfano.

Angalia msimbo MAANDISHI

c1|c2|c3 -------- 1 |5 |8

Hasara ya kutumia subqueries, ikilinganishwa na maswali kadhaa tofauti, ni kasi ya utekelezaji na mzigo kwenye hifadhidata.

Mfano ufuatao wa hoja iliyo na COUNT nyingi katika swali moja la MySQL imeundwa kwa njia tofauti kidogo, hutumia IF(condition, value1, value2) constructs, pamoja na SUM(). Inakuruhusu kuchagua data kulingana na vigezo maalum ndani ya hoja moja, kisha ufupishe, na uonyeshe maadili kadhaa kama matokeo.

Angalia msimbo MYSQL

Kama inavyoonekana kutoka kwa ombi, ilijengwa kwa ufupi kabisa, lakini kasi ya utekelezaji wake pia haikuwa ya kupendeza, matokeo ya ombi hili yatakuwa kama ifuatavyo.

Angalia msimbo MAANDISHI

jumla|c1|c2|c3 -------------- 14 |1 |5 |8

Ifuatayo, nitatoa takwimu za kulinganisha juu ya kasi ya utekelezaji wa chaguo tatu za hoja kwa kuchagua COUNT (). Ili kupima kasi ya utekelezaji wa hoja, maswali 1000 ya kila aina yalitekelezwa, na jedwali lililo na rekodi zaidi ya elfu tatu. Zaidi ya hayo, kila wakati ombi lilikuwa na SQL_NO_CACHE kuzima uhifadhi wa matokeo na hifadhidata.

Kasi ya utekelezaji
Maombi matatu tofauti: sekunde 0.9
Hoja moja yenye hoja ndogo: sekunde 0.95
Ombi moja la IF na SUM construct: 1.5 sec

Hitimisho. Na kwa hiyo, tuna chaguo kadhaa kwa ajili ya kujenga maswali kwenye hifadhidata ya MySQL na COUNT kadhaa (), chaguo la kwanza na maswali tofauti sio rahisi sana, lakini ina matokeo bora ya kasi. Chaguo la pili na subqueries ni rahisi zaidi, lakini kasi ya utekelezaji wake ni chini kidogo. Na hatimaye, toleo la tatu la lakoni la swala na IF na SUM hujenga, ambayo inaonekana kuwa rahisi zaidi, ina kasi ya chini ya utekelezaji, ambayo ni karibu mara mbili chini kuliko chaguzi mbili za kwanza. Kwa hivyo, wakati wa kuongeza utendakazi wa hifadhidata, ninapendekeza kutumia toleo la pili la hoja iliyo na subqueries na COUNT (), kwanza, kasi ya utekelezaji wake iko karibu na matokeo ya haraka sana, na pili, shirika kama hilo ndani ya swala moja ni rahisi sana. .

Katika somo lililopita tulikumbana na usumbufu mmoja. Tulipotaka kujua ni nani aliyeunda mada ya "baiskeli", tulituma ombi linalolingana:

Badala ya jina la mwandishi, tulipokea kitambulisho chake. Hii inaeleweka, kwa sababu tulifanya swali kwenye jedwali moja - Mada, na majina ya waandishi wa mada huhifadhiwa kwenye jedwali lingine - Watumiaji. Kwa hivyo, baada ya kupata kitambulisho cha mwandishi wa mada, tunahitaji kuuliza swali lingine - kwa Jedwali la Watumiaji ili kujua jina lake:

SQL hutoa uwezo wa kuchanganya maswali kama haya kuwa moja kwa kugeuza moja yao kuwa subquery (swali lililowekwa). Kwa hivyo, ili kujua ni nani aliyeunda mada "baiskeli", tutafanya swali lifuatalo:

Hiyo ni, baada ya neno kuu WAPI, tunaandika ombi lingine katika hali hiyo. MySQL kwanza huchakata hoja ndogo, inarudisha id_author=2, na thamani hii inapitishwa kwa kifungu. WAPI ombi la nje.

Kunaweza kuwa na subqueries kadhaa katika swala moja, syntax ya hoja kama hii ni kama ifuatavyo: Kumbuka kwamba subqueries inaweza kuchagua safu moja tu, maadili ambayo yatarudi kwa hoja ya nje. Kujaribu kuchagua safu wima nyingi kutasababisha hitilafu.

Ili kujumuisha hili, hebu tufanye ombi lingine na tujue ni ujumbe gani mwandishi wa mada ya "baiskeli" aliacha kwenye jukwaa:

Sasa wacha tufanye kazi ngumu, tujue ni mada gani mwandishi wa mada ya "baiskeli" aliacha ujumbe:

Hebu tujue jinsi inavyofanya kazi.

  • MySQL itatekeleza swali la kina zaidi kwanza:

  • Matokeo yanayotokana (id_author=2) yatapitishwa kwa ombi la nje, ambalo litachukua fomu:

  • Matokeo yanayotokana (id_topic:4,1) yatapitishwa kwa ombi la nje, ambalo litachukua fomu:

  • Na itatoa matokeo ya mwisho (topic_name: kuhusu uvuvi, kuhusu uvuvi). Wale. mwandishi wa mada ya "baiskeli" aliacha ujumbe katika mada ya "Kuhusu uvuvi" iliyoundwa na Sergei (id=1) na katika mada ya "Kuhusu uvuvi" iliyoundwa na Sveta (id=4).
Hiyo ndiyo yote nilitaka kusema juu ya maswali yaliyowekwa. Ingawa, kuna mambo mawili ya kuzingatia:
  • Haipendekezi kuunda maswali kwa kiwango cha nesting zaidi ya tatu. Hii inasababisha kuongezeka kwa muda wa utekelezaji na ugumu katika kuelewa kanuni.
  • Sintaksia iliyotolewa kwa hoja zilizowekwa kiota ndiyo inayojulikana zaidi, lakini sio pekee. Kwa mfano, badala ya kuuliza

    andika

    Wale. tunaweza kutumia waendeshaji wowote wanaotumiwa na neno kuu la WHERE (tulizisoma katika somo lililopita).
Oktoba 9, 2008 saa 11:37 jioni Kuboresha hoja za MySQL
  • MySQL

Katika kazi ya kila siku, unakutana na makosa sawa wakati wa kuandika maswali.

Katika nakala hii ningependa kutoa mifano ya jinsi ya KUTOKUANDISHA maswali.

  • Chagua sehemu zote
    CHAGUA * KUTOKA mezani

    Wakati wa kuandika maswali, usitumie uteuzi wa nyanja zote - "*". Orodhesha sehemu ambazo unahitaji sana. Hii itapunguza kiasi cha data inayoletwa na kutumwa. Pia, usisahau kuhusu kufunika indexes. Hata kama unahitaji sehemu zote kwenye jedwali, ni bora kuziorodhesha. Kwanza, inaboresha usomaji wa nambari. Wakati wa kutumia nyota, haiwezekani kujua ni mashamba gani yaliyo kwenye meza bila kuiangalia. Pili, baada ya muda, idadi ya safu kwenye jedwali lako inaweza kubadilika, na ikiwa leo kuna safu tano za INT, basi katika mwezi TEXT na mashamba ya BLOB yanaweza kuongezwa, ambayo itapunguza kasi ya uteuzi.

  • Maombi katika mzunguko.
    Unahitaji kuelewa kwa uwazi kuwa SQL ni lugha inayotumika. Wakati mwingine waandaaji wa programu ambao wamezoea kufikiria katika suala la lugha za kitaratibu hupata shida kuhamisha mawazo yao kwa lugha ya seti. Hii inaweza kufanywa kwa urahisi kwa kupitisha sheria rahisi - "usitekeleze maswali kwa kitanzi." Mifano ya jinsi hii inaweza kufanywa:

    1. Sampuli
    $news_ids = get_list("CHAGUA kitambulisho cha habari_KUTOKA leo_habari");
    wakati($news_id = get_next($next_ids))
    $news = get_row("CHAGUA kichwa, mwili KUTOKA habari WAPI news_id = ". $news_id);

    Sheria ni rahisi sana - maombi machache, bora (ingawa kuna tofauti na hii, kama sheria yoyote). Usisahau kuhusu IN() ujenzi. Nambari iliyo hapo juu inaweza kuandikwa kwa swali moja:
    CHAGUA kichwa, mwili KUTOKA_habari_habari INNER JIUNGE KWA KUTUMIA (kitambulisho_cha_cha_habari)

    2. Ingizo
    $logi = parse_log();
    wakati($rekodi = inayofuata($logi))
    query("INGIA KWENYE kumbukumbu SET thamani = ". $log["value"]);!}

    Ni bora zaidi kubatilisha na kutekeleza swali moja:
    INGIA KWENYE kumbukumbu (thamani) THAMANI (...), (...)

    3. Sasisho
    Wakati mwingine unahitaji kusasisha safu nyingi kwenye jedwali moja. Ikiwa thamani iliyosasishwa ni sawa, basi kila kitu ni rahisi:
    SASISHA SET kichwa cha habari = "test" WHERE id IN (1, 2, 3).!}

    Ikiwa thamani inayobadilishwa ni tofauti kwa kila rekodi, basi hii inaweza kufanywa kwa hoja ifuatayo:
    SASISHA SET ya habari
    title = KESI
    WAKATI habari_id = 1 BASI "aa"
    WAKATI news_id = 2 KISHA "bb" ILIPOISHIA
    WAPI kitambulisho cha habari (1, 2)

    Vipimo vyetu vinaonyesha kuwa ombi kama hilo ni mara 2-3 haraka kuliko maombi kadhaa tofauti.

  • Kufanya shughuli kwenye sehemu zilizoorodheshwa
    CHAGUA kitambulisho cha mtumiaji KUTOKA kwa watumiaji WAPI blogs_count * 2 = $value

    Hoja hii haitatumia faharasa, hata kama safu wima ya blogs_count imeorodheshwa. Ili faharasa itumike, hakuna mabadiliko lazima yafanywe kwenye sehemu iliyoonyeshwa kwenye hoja. Kwa maombi kama haya, sogeza vitendaji vya ubadilishaji hadi sehemu nyingine:
    CHAGUA kitambulisho cha mtumiaji KUTOKA kwa watumiaji AMBAPO blogs_count = $value / 2;

    Mfano sawa:
    CHAGUA kitambulisho cha mtumiaji KUTOKA kwa watumiaji WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(imesajiliwa) = DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY);
    mapenzi.

  • Inaleta safu mlalo ili tu kuhesabu idadi yao
    $result = mysql_query("CHAGUA * KUTOKA meza", $link);
    $num_rows = mysql_num_rows($matokeo);
    Iwapo unahitaji kuchagua idadi ya safu mlalo zinazokidhi hali fulani, tumia hoja ya SELECT COUNT(*) KUTOKA kwenye jedwali badala ya kuchagua safu mlalo zote ili tu kuhesabu idadi ya safu mlalo.
  • Inaleta safu mlalo za ziada
    $result = mysql_query("CHAGUA * KUTOKA meza1", $ kiungo);
    while($row = mysql_fetch_assoc($matokeo) && $i< 20) {

    }
    Iwapo unahitaji n kuleta safu mlalo, tumia LIMIT badala ya kutupa safu mlalo za ziada kwenye programu.
  • Kwa kutumia ORDER BY RAND()
    CHAGUA * KUTOKA KWA jedwali ORDER BY RAND() LIMIT 1;

    Ikiwa meza ina safu zaidi ya elfu 4-5, basi ORDER BY RAND() itafanya kazi polepole sana. Itakuwa bora zaidi kutekeleza maswali mawili:

    Ikiwa jedwali lina kitufe cha msingi cha_auto_increment na hakuna mapungufu:
    $rnd = rand(1, swala("CHAGUA MAX(id) KUTOKA jedwali");
    $ safu = swala("CHAGUA * KUTOKA jedwali WAPI kitambulisho = ".$rnd);

    Au:
    $cnt = swala("CHAGUA COUNT(*) KUTOKA jedwali");
    $ safu = swali("CHAGUA * KUTOKA KIKOMO cha jedwali ".$cnt.", 1");
    ambayo, hata hivyo, inaweza pia kuwa polepole ikiwa kuna idadi kubwa sana ya safu kwenye jedwali.

  • Kwa kutumia idadi kubwa ya JIUNGE
    CHAGUA
    v.kitambulisho_cha_video
    a.jina,
    g.aina
    KUTOKA
    video AS v
    KUSHOTO JIUNGE
    link_actors_videos AS la ON la.video_id = v.video_id
    KUSHOTO JIUNGE
    waigizaji AS a ON a.actor_id = la.actor_id
    KUSHOTO JIUNGE
    link_genre_video AS lg ILIYO lg.video_id = v.video_id
    KUSHOTO JIUNGE
    aina AS g ILIYO g.genre_id = lg.genre_id

    Ni lazima ikumbukwe kwamba wakati wa kuunganisha meza moja hadi nyingi, idadi ya safu katika uteuzi itaongezeka kwa kila JIUNGE ijayo Kwa kesi kama hizo, ni haraka kugawanya swala kama hilo katika kadhaa rahisi.

  • Kwa kutumia LIMIT
    CHAGUA... KUTOKA jedwali LIMIT $start, $per_page

    Watu wengi wanafikiri kuwa swala kama hilo litarudisha $per_page ya rekodi (kawaida 10-20) na kwa hivyo itafanya kazi haraka. Itafanya kazi haraka kwa kurasa chache za kwanza. Lakini ikiwa idadi ya rekodi ni kubwa, na unahitaji kutekeleza CHAGUA... KUTOKA jedwali LIMIT 1000000, swala 1000020, kisha kutekeleza swali kama hilo, MySQL itachagua kwanza rekodi 1000020, kutupa milioni ya kwanza na kurudisha 20. Hii inaweza isiwe haraka hata kidogo. Hakuna njia zisizo na maana za kutatua tatizo. Wengi huweka tu idadi ya kurasa zinazopatikana kwa nambari inayofaa. Unaweza pia kuharakisha maswali kama haya kwa kutumia faharisi za kufunika au suluhisho za watu wengine (kwa mfano sphinx).

  • Si kutumia KWENYE DUPLICATE KEY UPDATE
    $ safu = swala("CHAGUA * KUTOKA jedwali WAPI kitambulisho = 1");

    Ikiwa (safu ya $)
    swala("USASISHA jedwali SET safuwima = safu wima + 1 WHERE id=1")
    mwingine
    swala("INGIZA KWENYE jedwali SET safuwima = 1, id=1");

    Muundo kama huo unaweza kubadilishwa na swali moja, mradi tu kuna ufunguo wa msingi au wa kipekee wa uga wa kitambulisho:
    WEKA NDANI YA jedwali WEKA safu wima = 1, id=1 KWENYE DUPLICATE KEY UPDATE safu wima = safu + 1

Soma