2009-07-22 13 views
25

PHP में प्रोग्रामिंग करते समय मैं हमेशा अर्थपूर्ण 'मॉडल' (कक्षाएं) बनाने की कोशिश करता हूं जो डेटाबेस में तालिकाओं से मेल खाते हैं। मुझे अक्सर निम्नलिखित समस्या का सामना करना पड़ता है:स्वच्छ ओओ-संरचना बनाम एसक्यूएल प्रदर्शन

मान लीजिए कि मैंने दो तालिकाओं के साथ डेटाबेस बनाया है: authors और blogs, दोनों मेरे आवेदन में एक समान मॉडल है।

मान लीजिए कि मैं लेखक के बारे में जानकारी के साथ-साथ सभी ब्लॉगों प्रिंट करना चाहते हैं, मैं इस तरह कुछ करने के लिए चाहते हैं:

<?php 
foreach ($app->getBlogs() as $blog) { 
    echo "<h1>" . $blog->title . "</h1>"; 
    echo "Written by" . $blog->getAuthor()->name . "</p>"; 
    // ... et cetera 
} 
?> 

समस्या यह है कि आवेदन होगा अब आग 1 SQL क्वेरी के लिए प्रत्येक लेखक के लिए जानकारी प्राप्त करने के लिए सभी ब्लॉग आइटम, और [ब्लॉग आइटम की संख्या] प्रश्न प्राप्त करें। इस्तेमाल किया सरल एसक्यूएल होने मैं एक साधारण क्वेरी का उपयोग कर इस जानकारी को पुनः प्राप्त किया जा सकता था:

SELECT * FROM blogs 
JOIN authors ON authors.id = blogs.author 

इस तरह के मुद्दों से निपटने का सबसे अच्छा तरीका क्या है: बहुत से बेकार एसक्यूएल प्रश्नों को क्रियान्वित करने के बिना एक वस्तु उन्मुख आवेदन का विकास।

उत्तर

3

आईएमओ, मुझे लगता है कि आपको सिर्फ एक और कक्षा लिखनी चाहिए जो आपके पास है जो आपके पास है। क्या ब्लॉग हमेशा एक लेखक के लिए यह समझ में आता है? क्या प्रत्येक लेखक के पास ब्लॉग है? क्या एक लेखक के पास कई ब्लॉग हैं? इन मुद्दों के बारे में सोचें, फिर एक कक्षा तैयार करें जो इसे समाहित करेगी। याद रखें, ठेठ डेटाबेस स्कीमा ओओ नहीं हैं ... वे संबंधपरक हैं। हाँ, वे करीब हैं, लेकिन सूक्ष्म मतभेद हैं।

तो यदि किसी लेखक के पास एकाधिक ब्लॉग हो सकते हैं, तो आपके पास किसी प्रकार की बहुविकल्पीय वर्ग (लेखक आईडी पर आधारित कुंजी के साथ) की कुंजी हो सकती है और आप इस वर्ग को एक SQL कॉल के साथ प्रारंभ या लोड कर सकते हैं। बस सोचने के लिए कुछ।

1

जो भी समाधान आप उपयोग करते हैं, ओआरएम या नहीं, इस मामले में एक भी चयन जारी करने में सक्षम होना चाहिए, और यह केवल आवश्यक कॉलम चुनने में सक्षम होना चाहिए। फिर उसमें शामिल होने से लेखकों की वस्तुओं को प्रति लेखक ब्लॉग की संबंधित सूचियों के साथ पॉपुल करने में सक्षम होना चाहिए। एकाधिक एसक्यूएल जारी करने के लिए अपमानजनक है।

0

यह क्लासिक ORM समस्या है। विचार के कई स्कूल। PHP विनिर्देशों के बारे में निश्चित नहीं है, लेकिन इस 'बाधा मेल खाने' को हल करने के लिए कई रणनीतियां हैं। गूगल ओआरएम

2

इस तरह की चीजें बिल्कुल आपके डेटा परत को बनाने के लिए हल करनी चाहिए। अपने ब्लॉग के लिए अपने मॉडल में, एक ब्लॉग होना चाहिए जैसे किब्लॉगब्लिस्ट() जो ब्लॉग टाइटल और लेखक का नाम सभी को एक प्रश्न में वापस कर देगा।

+0

कुछ प्रकार के समाधान मैंने खुद के बारे में सोचा है लेकिन मुद्दा यह है: लेखक की ऑब्जेक्ट की आवश्यकता होने पर मुझे पहले से पता नहीं है, $ ब्लॉग-> getAuthor() को कभी भी कॉल नहीं किया जा सकता है लेकिन मैं पुनः प्राप्त कर लिया होता बशर्ते समाधान के साथ जानकारी। – Thijs

+0

आप जो पूछ रहे हैं वह असंभव है। आप मूल रूप से उस कोड के लिए पूछ रहे हैं जो किसी भी तरह से पहले से जानता है कि आप क्या उपयोग करने जा रहे हैं। आपको इसे खुद को हार्डकोड करना होगा; आपको या तो आलसी लोडिंग चुननी है, जो कि यदि आप केवल कुछ लेखकों को चाहते हैं, लेकिन सभी नहीं, या बैच लोडिंग, जैसा ऊपर वर्णित है, तो कुशल है, यदि आपको कई लेखकों की आवश्यकता है तो यह कुशल है। आप दोनों नहीं हो सकता है। – ryeguy

+0

इंटेक में हम जिस ओआरएम टूल का उपयोग करते हैं, वह (ए) एक लेखक को खींचने के लिए कक्षाएं उत्पन्न करता है और अन्य (बी) लेखकों के संग्रह को खींचने के लिए। तो मैं आसानी से कह सकता था "मुझे उन सभी लेखकों को प्राप्त करें जिनके पास पहले नाम में अक्षर 'एम' है या लगभग कुछ भी है। हालांकि, दोनों (ए) और (बी) पूरे लेखक को खींचते हैं, इसलिए सभी फ़ील्ड तार भर जाते हैं। यदि आप किसी विशेष मामले के लिए केवल एक फ़ील्ड चाहते थे, या यदि आपको असामान्य शामिल होने की आवश्यकता है, तो आपको इसे स्वयं लिखना होगा। जो ठीक है मैं gen'd कोड का 90% समय का उपयोग करता हूं। –

0

ऐसा करने का एक तरीका यह है कि इसमें शामिल होने के लिए एक दृश्य बनाएं और मानचित्र दृश्य परिणाम किसी अन्य वर्ग में जाएं जिसमें ब्लॉग और लेखक के लिए डेटा शामिल है।

1

प्रोपेल एक PHP ओआरएम का एक उदाहरण है जो इसका सामना कर सकता है। मुझे यकीन है कि सिद्धांत ऐसा करने में सक्षम होना चाहिए, हालांकि मैंने इसे कभी नहीं देखा है।

पहिया को फिर से क्यों शुरू करें?

3

जब तक आप इस तथ्य के बारे में नहीं जानते कि अक्षम एसक्यूएल संचालन का कोई वास्तविक प्रभाव नहीं होगा, जैसे कि अनावश्यक पुनरावृत्तियों की संख्या या प्रभावित पंक्तियां हमेशा छोटी होंगी (उदाहरण के लिए परिवार में बच्चों की संख्या पर एक ऑपरेशन करना, जो, डुगर्स जैसे दुर्लभ मामलों से कम, 10 से कम होने पर भरोसा किया जा सकता है), मैंने हमेशा ओओ कोड की सुंदरता पर संबंधपरक क्वेरी की दक्षता का पक्ष लिया है।

हालांकि बदसूरत ओओ कोड रखरखाव को दर्द बना सकता है, अक्षम डेटा एक्सेस अपने सिस्टम को घुटनों पर ला सकता है, आमतौर पर जब आप छुट्टी पर रहते हैं या सोने की कोशिश करते हैं। और अधिकांश समय, आप एक अच्छा समझौता पा सकते हैं जो सबसे कुशल SQL संचालन को एक उचित "ऑब्जेक्ट" इंटरफ़ेस बनाता है। यदि आपका ऑब्जेक्ट मॉडल सुंदर नहीं है, तो यह आपके लिए थोड़ा अधिक समय ले सकता है यदि आपके ऑब्जेक्ट मॉडल सुंदर नहीं हैं, लेकिन यह आपके ग्राहकों को उस बटन को हर बार समय पर खर्च कर रहा है (या बड़े हार्डवेयर के मामले में पैसा चलाने के लिए ऐप - ऑप्टिमाइज़ेशन का कभी भी एक अच्छा तरीका नहीं है), और ऐप का उपयोग करके बिताए गए आदमी के घंटों को उस आदमी के घंटों को दूर करने के लिए दूर करना चाहिए (एक उम्मीद करेगा)।

जहां तक ​​आपकी इंटरफ़ेस की आवश्यकता होगी, इस बारे में आपकी चिंताओं की आवश्यकता होगी (आपको सभी संभावित खपत पैटर्न को समझने के लिए मजबूर करना), मैंने संग्रहित प्रक्रियाओं के माध्यम से अपने सभी डेटा संशोधन करके इसका सामना किया है, लेकिन डेटा पहुंच को सीधे जाने की अनुमति है सभी उपयोगकर्ताओं को केवल विशेषाधिकार चुनकर टेबल & विचारों के खिलाफ। यह एक अर्द्ध विवादास्पद स्थिति है, क्योंकि बहुत से लोग डाउनस्ट्रीम उपभोक्ताओं से सभी डेटा एक्सेस ऑपरेशंस को लॉक करना चाहते हैं ताकि यह सुनिश्चित किया जा सके कि सभी वर्ग चलाना उनके मानकों पर है। लेकिन डेटा को देखने के नए तरीके हमेशा आ रहे हैं, और यदि आपको एक नई संग्रहित प्रो को जोड़ना है, तो अपनी कोर क्लास लाइब्रेरी अपडेट करें और हर बार कोई नया फीचर लागू करने के लिए अपने क्लाइंट कोड को अपडेट करें, तैनाती और योग्यता बढ़ सकती है एक असली बोझ बनें - एक ऑब्जेक्ट मॉडल से निपटने के मुकाबले कहीं ज्यादा जो धार्मिक आदर्श फिट नहीं है। और कोड निरीक्षण प्रक्रिया को कार्यान्वित करना बहुत आसान है जो सत्यापित करता है कि डाउनस्ट्रीम उपभोक्ताओं द्वारा लिखे गए नए चयन विवरण कोशेर हैं।

0

ईमानदारी से, बस अपने ब्लॉग वर्ग कहा जाता getBlogsWithAuthors पर एक विधि बनाने के() और फिर

SELECT * 
FROM blogs 
JOIN authors 
     ON authors.id = blogs.author 

चलाने मैं जानता हूँ कि यह एक दर्द एक मॉडल वर्ग के लिए इस तरह सामान लिखने के लिए की तरह लग सकता है, लेकिन वहाँ वास्तव में है कोई और तरीका नहीं। आप इसे थोड़ा और अधिक गतिशील बना सकता है, तथापि:

//this is a method of a model class. 
//Assume $this->table is the table name of the model (ie, Blog) 
public function getWith($joinTable, $pivot1, $pivot2) 
{ 
    $sql="SELECT * 
      FROM {$this->table} 
      JOIN $joinTable 
        ON $pivot1 = $pivot2"; 

    return executeQuery($sql);  
} 

$blog=new Blog(); 
$result=$blog->getWith('authors', 'authors.id', 'blogs.author'); 
[play with results here] 
+0

ईमानदार होने के लिए, यह समाधान मेरे लिए थोड़ा हैकी लगता है। GetWith() विधि बहुत वर्णनात्मक नहीं है और ऑब्जेक्ट-ओरिएंटेड डिज़ाइन द्वारा समर्थित encapsulation को अनुरूप नहीं करती है क्योंकि अन्य ऑब्जेक्ट्स को ब्लॉग क्लास (कॉलम नाम, उम्मीदवारों में शामिल होने) के आंतरिक कार्यों को जानना होता है। – Thijs

+0

वैसे यह विचार था कि यह आपके बेस मॉडल वर्ग में हो सकता है और किसी भी मॉडल के लिए किसी भी हार्डकोडिंग के बिना अनुकूलित किया जा सकता है। यदि आप कुछ और सुरुचिपूर्ण चाहते हैं, तो आप इसे मैन्युअल रूप से क्यों कोड कर रहे हैं? प्रोपेल या सिद्धांत के लिए जाओ। आप अन्यथा पहिया को फिर से शुरू कर रहे हैं। – ryeguy

+0

मुझे लगता है कि राईगुय इस पर सही है। ;) अगर उसका समाधान हैकिश है, तो ऐसा इसलिए है क्योंकि यह बहुत ही सरल है। मुझे डेटाबेस तत्वों को टेक्स्ट के रूप में पास करना पसंद नहीं है। लेकिन अगला कदम क्या है? स्तंभों के लिए अधिक टूलिंग (enums, आदि) के साथ प्रत्येक इकाई के लिए एक अलग वर्ग बनाना।लेकिन वह समय लेने वाला और भंगुर है (डेटाबेस परिवर्तन आदि के बारे में सोचें), तो अगला क्या है? कोड पीढ़ी एक टन हल करता है। और यदि कोड पीढ़ी है, तो जीई हम बहुत कुछ कर सकते हैं। और इसी तरह मेरा ओआरएम उपकरण पैदा हुआ था। कक्षाओं को उत्पन्न करने के लिए एमएस एक्सेस का उपयोग करके यह सचमुच एएसपी क्लासिक में शुरू हुआ। :) –

3

मैं एक बहुत बड़ा ORM वकील हूँ, और यहाँ है मेरी वजन-इन:

यह एक टन के लिए आवेदन प्रदर्शन का एक inperceptible राशि व्यापार करने के लिए ठीक है डेवलपर प्रदर्शन का। सर्वर इन दिनों बेहद शक्तिशाली हैं और अतिरिक्त लोहे हमें कुछ नई लचीलापन देता है।

उस ने कहा, अगर आप कुछ मूर्खतापूर्ण करते हैं जो सर्वर को अपने घुटनों पर लाकर उपयोगकर्ता अनुभव को समाप्त करता है, तो यह ठीक नहीं है। यदि आपके उदाहरण में आपके पास लाखों लेखक थे, तो उन्हें अपने सभी क्षेत्रों के साथ नीचे खींचकर और उनके माध्यम से फिर से चलना मूर्खतापूर्ण होगा। यदि आपके पास केवल 20 लेखकों थे, तो यह कोई बड़ा सौदा नहीं है।

विशाल डेटासेट और महंगे बैच ऑपरेशंस के मामले में, एक ओआरएम लड़के के रूप में, मुझे केवल उस मामले के लिए विशेष स्पॉक्स या एसक्यूएल स्टेटमेंट को अनुकूलित और लिखना होगा। और मुझे सावधान रहना होगा कि मैं अपना कोड इस तरह से लिखूं कि मैं डेटाबेस को हथौड़ा दूंगा, एक कैशिंग पैटर्न का उपयोग करना बेहतर होगा जहां मैं एक बड़ा डेटा सेट खींचता हूं और फिर उस से काम करता हूं।

यह एक बड़ी बहस वाली बहस है, लेकिन मेरे लिए यह समझने की बात है कि आप एक ही उपकरण के साथ हर समस्या को हल नहीं कर सकते हैं।

+0

आपकी टिप्पणी के लिए धन्यवाद। प्रदर्शन और साफ डिजाइन के बीच कभी व्यापार-बंद होगा? क्या पुन: प्रयोज्य और साफ ऑब्जेक्ट-ओरिएंटेड कोड दोनों लिखने का कोई तरीका नहीं है और सही डेटा चुनने में कुशल क्वेरी निष्पादित करें? – Thijs

+0

thijs: मुझे लगता है कि आप अपना केक ले सकते हैं और इसे भी खा सकते हैं। यदि आपको एक-ऑफ एसक्यूएल कथन लिखना है, तो बस अपने आवेदन के दौरान एक पैटर्न का उपयोग करके कक्षा में डेटा एक्सेस कोड को समाहित करने के लिए अपना सर्वश्रेष्ठ प्रयास करें। यह घृणित नहीं होना चाहिए। ;) मेरे पास ऐसी परियोजनाएं हैं जहां 'स्पॉक्स' नामक एक कक्षा है जिसमें मेरी सभी संग्रहीत प्रक्रियाओं में शामिल होने के लिए कोड शामिल है। तो मैं कुछ ऐसा कर सकता हूं: myData = Sprocs.AuthorNames, और यह बहुत संगत है। कई ओआरएम उपकरण आपके लिए उस तरह की चीजें उत्पन्न करते हैं, जो कि अच्छा है। –

+0

आप कैसे जानते हैं कि आपके पास 20 लेखकों हैं जब उपयोगकर्ता किसी भी समय अधिक जोड़ सकते हैं? क्या आप तालिका में पंक्तियों की संख्या पर जांच की बाधा डालते हैं या क्या? इस प्रकार की क्षमता योजना एक आपदा होने का इंतजार कर रही है। – wqw

1

मैं कुछ अन्य बाइंडिंग .. उदाहरण के लिए इस्तेमाल किया:

<?php 
$blogs = $app->getBlogs(); 
$blogs->getAuthor(); 
foreach ($blogs as $blog) { 
    echo "<h1>" . $blog->title . "</h1>"; 
    echo "Written by" . $blog->getAuthor()->name . "</p>"; 
    // ... et cetera 
} 
?> 

-> getAuthor() $ ब्लॉग पर कॉल सरणी के लिए विशेष वस्तु का उपयोग कर केवल एक बार डीबी क्वेरी करता है, और, getAuthor() कॉल पर कहा जाता है प्रत्येक (लेकिन, किसी भी तरह से केवल एक क्वेरी के रूप में चलाने के लिए अनुकूलित किया गया है)।

0

आप हमेशा मध्यवर्ती परत के रूप में memcached का उपयोग कर सकते हैं। प्रत्येक क्वेरी पूरी तरह से रैम-आधारित होगी, जिसका अर्थ है कि आप जितनी चाहें उतनी दौड़ सकते हैं।

1

आप पहले से ही प्रश्न का उत्तर दिया:

सीधा एसक्यूएल इस्तेमाल किया करने के बाद मैं इस जानकारी एक साधारण क्वेरी

आप एसक्यूएल कि को हासिल करेगा केवल ब्लॉग के बीच एक विकल्प है का उपयोग कर लिया गया हो सकता था पोस्ट और एसक्यूएल जो ब्लॉग पोस्ट और लेखकों को प्राप्त करता है। इसी प्रकार आपके पास कुछ PHP कोड के बीच एक विकल्प है जो को ब्लॉग पोस्ट या PHP कोड प्राप्त करता है जो ब्लॉग पोस्ट और लेखकों को प्राप्त करता है। आपको अपने PHP कोड के बारे में एक विकल्प बनाना है, जैसे आपको अपने एसक्यूएल के बारे में कोई विकल्प बनाना है।

उपरोक्त कई उदाहरण हैं जो दर्शाते हैं कि यह अभ्यास में कैसे काम करेगा। सिद्धांत या प्रोपेल का उपयोग करने की सिफारिश भी एक अच्छी है।

1

ग्रेग यंग और मार्टिन फाउलर द्वारा वर्णित कमांड/क्वेरी सेपरेशन पर विचार करें। आपके प्रेजेंटेशन मॉडल के लिए डीटीओ को पुनः प्राप्त करने के लिए अनुकूलित एक टेबल में आपके क्वेरी मॉडल में ब्लॉग और लेखक को सामान्यीकृत किया जा सकता है।

ग्रेग यंग के पास इन्फोक्यू पर सीक्यूएस पर एक महान प्रस्तुति है।

संबंधित मुद्दे