<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
> <channel><title>Project 2061 Techlog &#187; MySQL</title> <atom:link href="http://techlog.p2061.org/category/mysql/feed/" rel="self" type="application/rss+xml" /><link>http://techlog.p2061.org</link> <description>Blogging from Project 2061 technology group</description> <lastBuildDate>Tue, 06 Sep 2011 14:49:39 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <item><title>Moving from Microsoft Access to MySQL</title><link>http://techlog.p2061.org/2010/02/26/moving-from-microsoft-access-to-mysql/</link> <comments>http://techlog.p2061.org/2010/02/26/moving-from-microsoft-access-to-mysql/#comments</comments> <pubDate>Fri, 26 Feb 2010 17:58:40 +0000</pubDate> <dc:creator>bsweeney</dc:creator> <category><![CDATA[IERI]]></category> <category><![CDATA[MySQL]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[asp]]></category> <category><![CDATA[msaccess]]></category> <guid
isPermaLink="false">http://techlog.p2061.org/?p=298</guid> <description><![CDATA[We recently decided to make a public release of an old web-based application coded in ASP (classic, using VBScript) and using Microsoft Access. In order to make this application public we need to make a few modifications, not the least of which is moving from Microsoft Access to MySQL. Using Microsoft Access on the back-end [...]]]></description> <content:encoded><![CDATA[<p>We recently decided to make a public release of an <em>old</em> web-based application coded in ASP (classic, using VBScript) and using Microsoft Access. In order to make this application public we need to make a few modifications, not the least of which is moving from Microsoft Access to MySQL. Using Microsoft Access on the back-end would significantly hamper the ability of the application to support concurrent users, among other issues.</p><p>The majority of the coding modifications have yet to be made, but the database switch has already occurred. In the process of moving from MS Access to MySQL I discovered a few settings that would be helpful should this action need to be performed for other applications. These settings should enable similar applications to be moved with minimal modification to the programming.</p><p>First, let&#8217;s review some settings related to the MySQL ODBC driver. The settings are relevant to all versions of the driver, but the name of the setting may be different on different versions (I&#8217;m using 5.1.6). Here are the options which should be selected:</p><ul><li>Return matched rows instead of affected rows</li><li>Treat BIGINT columns as INT columns</li><li>Enable safe options</li></ul><p>The following information relates more generally to changes that may have to be made in the code:</p><ul><li>MySQL doesn&#8217;t really support server-side cursors so the ODBC drivers fakes it. This is, mostly, fine except that some properties of the Recordset object are not available (namely RecordCount). In order to get full cursor support you should change the location from the server to the client (<code>adUseClient</code> or the literal value 3).</li><li>ASP doesn&#8217;t understand non-signed integers. This causes problems when performing operations using these values unless you manually type the value in your script, e.g. <code>scriptvar = CInt(objrs("dbcol")</code>). The other solution is to make all integers signed. Otherwise you will see the error: Variable uses an Automation type not supported in VBScript.</li><li>Related to the above is the usage of values from the database in comparison functions. VBScript variables are typed (e.g. integer, string, boolean, etc.). Though you can&#8217;t specify the type during variable instantiation (with <code>Dim</code>) VBScript does pay attention to type when performing comparisons. When two variables of different types are compared you will get a &#8220;Type mismatch&#8221; error. The resolution is to <code>C<em>type</em></code> your variables if you run into this type of error.</li><li>Finally, check your SQL statements for any VBA function calls. These will either have to be modified into MySQL-compatible function calls or removed from the SQL code altogether.</li></ul><p>There are a number of issues that may be encountered when attempting to convert an ASP-based application from MS Access to MySQL. The issues addressed here are only those relevant to this particular application. Other applications may require additional or different solutions and settings.</p><p>Resources:</p><ul><li><a
href="http://www.cynergi.net/exportsql/">MS Access to MySQL migration script</a></li><li><a
href="http://dev.mysql.com/tech-resources/articles/vb-cursors-and-locks.html" class="broken_link">MySQL Developer Zone: MySQL CursorTypes, LockTypes, and CursorLocations</a></li><li><a
href="http://dev.mysql.com/doc/refman/5.1/en/connector-odbc-configuration.html">MySQL 5.1 Reference Manual: 21.1.4. Connector/ODBC Configuration</a></li><li><a
href="http://forums.mysql.com/read.php?37,56260">MySQL Forums: type confusion in asp</a></li><li><a
href="http://lists.mysql.com/mysql/50187">MySQL Lists: Problem with RecordCount with ASP &amp; MySQL </a></li></ul> ]]></content:encoded> <wfw:commentRss>http://techlog.p2061.org/2010/02/26/moving-from-microsoft-access-to-mysql/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>CakePHP and CURRENT_TIMESTAMP</title><link>http://techlog.p2061.org/2009/04/17/cakephp-and-current_timestamp/</link> <comments>http://techlog.p2061.org/2009/04/17/cakephp-and-current_timestamp/#comments</comments> <pubDate>Fri, 17 Apr 2009 20:15:54 +0000</pubDate> <dc:creator>bsweeney</dc:creator> <category><![CDATA[CakePHP]]></category> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <guid
isPermaLink="false">http://techlog.p2061.org/?p=229</guid> <description><![CDATA[As of cakePHP 1.2.1.8004 you can&#8217;t use CURRENT_TIMESTAMP as the default for a column. With MySQL when the default is set to CURRENT_TIMESTAMP the current date+time is inserted for a new row that doesn&#8217;t specifically define the value of the column. From what I can tell, when CakePHP specifies the values for all columns when [...]]]></description> <content:encoded><![CDATA[<p>As of cakePHP 1.2.1.8004 you can&#8217;t use CURRENT_TIMESTAMP as the default for a column. With MySQL when the default is set to CURRENT_TIMESTAMP the current date+time is inserted for a new row that doesn&#8217;t specifically define the value of the column.</p><p>From what I can tell, when CakePHP specifies the values for all columns when it creates a new record. A column with a defined default that is not specifically set by the user is manually set by CakePHP (rather than let MySQL handle defaults upon record insertion). But CakePHP doesn&#8217;t understand the CURRENT_TIMESTAMP keyword and so treats it as a string and wraps it in quotes. This breaks the resulting INSERT statement and you receive an error:</p><blockquote><p>Incorrect datetime value: &#8216;CURRENT_TIMESTAMP&#8217;</p></blockquote><p>Interestingly, columns that are named &#8220;created&#8221; and &#8220;modified&#8221; receive special handling by CakePHP. These columns are treated like auto-update columns by CakePHP and it sets them as expected. With the special handling of these columns in mind it is possible to get around the CURRENT_TIMESTAMP bug by following the recommended settings for created/modified columns, i.e. specifying the field as DATETIME with a default of NULL. CakePHP will automatically update the columns when inserting/updating records.</p><p>References:</p><ul><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/timestamp.html">MySQL Reference Manual: 10.3.1.1. TIMESTAMP Properties</a></li><li><a
href="http://book.cakephp.org/view/69/created-and-modified">CakePHP Cookbook: 3.7.2.3 created and modified</a></li></ul> ]]></content:encoded> <wfw:commentRss>http://techlog.p2061.org/2009/04/17/cakephp-and-current_timestamp/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>The Mechanical Turk Knows All</title><link>http://techlog.p2061.org/2008/11/21/the-mechanical-turk-knows-all/</link> <comments>http://techlog.p2061.org/2008/11/21/the-mechanical-turk-knows-all/#comments</comments> <pubDate>Fri, 21 Nov 2008 19:28:24 +0000</pubDate> <dc:creator>bsweeney</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <guid
isPermaLink="false">http://techlog.p2061.org/?p=91</guid> <description><![CDATA[With a large set of test packets in need of transcription, little time to do so, and even less desire to spend the money on temporary workers, I needed to think of some other way to perform the task. Luckily I was able to come up with a method using a tool from Amazon that [...]]]></description> <content:encoded><![CDATA[<p>With a large set of test packets in need of transcription, little time to do so, and even less desire to spend the money on temporary workers, I needed to think of some other way to perform the task. Luckily I was able to come up with a method using a tool from Amazon that proved relatively easy to implement. Mechanical Turk .</p><p><span
id="more-91"></span></p><p><strong>Data Collection Hassles</strong></p><p>For the past few years the Assessment team has sent out a large batch of items in what we call pilot tests. These tests are used to gauge the effectiveness of assessment items. The format consists of an item followed by a set of questions about the item (Was there anything confusing?, Did the picture help?, Is answer A correct?, etc.). The questions have set answers (Yes, No, Not Sure) and/or a space for the student to provide a short written response.</p><p>In previous years we have used temporary workers to input the student responses into the Items Utility. This proved to be extremely slow and relatively expensive.</p><p>Last year we attempted a new method of data collection using an automated system to capture the Yes/No/Not Sure responses. This system used optical mark recognition (OMR) and required the packets to be formatted in a consistent manner on each page. Formatted in this way we could create a master file indicating how to judge answer selection. This proved fairly successful, though we did have to outsource the scanning to a third party. The results of the scan came back as Excel documents. A little PHP coding and I easily imported the scanned data into the Items Utility. The main drawback was that we still had to hire temps to enter the written responses.</p><p>This year we embarked on a new automated scanning system for the Yes/No/Not Sure responses that proved even better than in previous years. This system uses an in-house scanner and design software. A lot of prep work had to be performed by the researchers to set up their test packets. And we did have to use specific printers to produce the packets. But I believe in the end we saved money, particularly since the majority of the leg work had already been done in figuring out how to import the data into the utility. The only snag is that we again had no way of capturing the written responses electronically.</p><p>However, one of the benefits to the new system is that in addition to creating a data file for the Yes/No/Not Sure values it can produce images of the scanned regions. At first I thought maybe we could find some way of performing character recognition on the scanned images. Unfortunately, there&#8217;s just no economical way to do that on hand-written text. So our only real option was, again, transcription by a human being. Past experience with the time and money required made the option unpalatable and we were likely going to just move ahead without the hand-written data.</p><p><strong>Enter the Turk</strong></p><p>Amazon recently released a web-based service, <a
href="http://aws.amazon.com/mturk/">Mechanical Turk</a> (MTurk), that provides access to a distributed workforce. The service provides a means of creating what Amazon calls &#8220;Human Intelligence Tasks&#8221; (HITs), tasks that are currently too complex for a computer but ideally suited for your average person. We decided to try the service out for transcription of the written responses.</p><p>Since MTurk is web-based, the HITs are set up as web pages. An online editor makes setting up HIT templates fairly simple, though it helps to know a bit of HTML. Each template consists of instructions and a form where the worker enters the requested information. It&#8217;s up to the requester to determine the amount paid for each HIT completed (starting as low as one cent). Amazon tacks on an overhead fee for each HIT that is completed by a worker and accepted by the requester.</p><p>The template uses variables to fill in each HIT with unique information. Once the template is set up you provide a data file that contains the variable data. MTurk then publishes your HITs on a public interface where anyone in the world with an internet connection can perform the work.</p><p><strong>Using MTurk</strong></p><p>As I said, the program we used to scan the packets is able to save scanned regions as images. These images were organized such that we could easily determine the packet/student/item combination based solely on the file name and directory in which the image was located. This information is all we needed to insert data into the Items Utility, and thus provided an easy identifier to use with MTurk.</p><p>To minimize the amount of time a worker spends on each HIT it&#8217;s good to try and have all the data the user needs on the screen. Since a MTurk HIT is a web page it can reference images located on external servers. I used URLs for the image scan as values for the template variables. The HIT displayed the image side by side with a text area where the workers could input the transcribed text.</p><p>Initially I thought to just link to the original images. A quick test, however, and I realized that the size of the images would be a problem. The images were larger than needed and any bandwidth constraints on the worker end would significantly increase the time per HIT. Smaller files were needed, and to save space I thought to dynamically resize the images using PHP. A sample proved the folly of this idea. Our system resources are limited and the processing power and memory required to enable this for more than a few simultaneous workers caused the HITs to load slower than if we hadn&#8217;t resized to begin with. In the end we decided to resize all images, a scenario we had avoided due to space constraints. The smaller image would be referenced on each HIT with a link to the full size in cases where a zoomed view might be benefitial.</p><p>Since Amazon tacks on a handling fee for each HIT I attempted to organize our HITs in a way that would work out best for both us and the workers. We needed HITs that could be completed quickly but that also collected sufficient data so that the cost-per-HIT would balance out against the amount of work required. Plus we were concerned about providing equitable pay for the work being done. Based on our testing we were able to make a determination of how many images per HIT and at what rate would keep our fees acceptable while also resulting in an equitable wage.</p><p>Our due dilligence paid off. We had <span>48,351 HITs comprised of 193,401 images. </span>The work was completed within a couple of days, which was beyond my wildest estimates. The amount paid and the time taken to complete the work was significantly less than what we would have paid to hire traditional temporary workesrs to do the same.</p><p>Once the work was complete MTurk provided a data file that included the original data along with the worker input, all the information we needed to import the data into the utility.</p><p><strong>Wrapping Up</strong></p><p>While this was a bit of a learning process, using MTurk to transcribe this data proved successful. I fully expect to use this system in the future. This has been more of a review of the process, but there were a few technical aspects involved. Rather than go into detail on these I&#8217;m providing links to the files involved which should provide sufficient information in that regard (except for perhaps the import script).</p><ul><li><a
href="http://techlog.p2061.org/wp-content/uploads/2008/12/filenamesphp.txt">PHP Script to Generate a List of Files</a></li><li><a
href="http://techlog.p2061.org/wp-content/uploads/2008/12/resizeimgphp.txt">PHP Script to Resize Images</a></li><li><a
href="http://techlog.p2061.org/wp-content/uploads/2008/11/files_noblankssample.csv">Data Set Sent to MTurk</a></li><li><a
href="http://techlog.p2061.org/wp-content/uploads/2008/11/template.htm">MTurk HIT Template</a></li><li><a
href="http://techlog.p2061.org/wp-content/uploads/2008/11/batch_3838_resultsample.csv">Result Data Set Provided by MTurk</a></li><li><a
href="http://techlog.p2061.org/wp-content/uploads/2008/11/mturk_importsample.txt">Simplified Result Data Set</a></li><li><a
href="http://techlog.p2061.org/wp-content/uploads/2008/12/mturk_importphp.txt">PHP Script to Import Data</a></li></ul> ]]></content:encoded> <wfw:commentRss>http://techlog.p2061.org/2008/11/21/the-mechanical-turk-knows-all/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>SQL Tricks: WHERE column IN (SELECT &#8230;)</title><link>http://techlog.p2061.org/2008/10/07/sql-tricks-where-column-in-select/</link> <comments>http://techlog.p2061.org/2008/10/07/sql-tricks-where-column-in-select/#comments</comments> <pubDate>Tue, 07 Oct 2008 19:38:14 +0000</pubDate> <dc:creator>bsweeney</dc:creator> <category><![CDATA[MySQL]]></category> <guid
isPermaLink="false">http://techlog.p2061.org/?p=104</guid> <description><![CDATA[I was trying to find a way to update some rows in a MySQL table where the condition for performing the update was based on a column in another table. Normally this isn&#8217;t an issue, just run UPDATE table ... WHERE key_column IN (SELECT key_column FROM ...). I was having some problems, however, because the [...]]]></description> <content:encoded><![CDATA[<p>I was trying to find a way to update some rows in a MySQL table where the condition for performing the update was based on a column in another table. Normally this isn&#8217;t an issue, just run <code>UPDATE table ... WHERE key_column IN (SELECT key_column FROM ...)</code>.</p><p>I was having some problems, however, because the table that needed to be updated uses a mutli-column primary key. Normally I would select the relevant rows using a <code>JOIN</code>. Unfortunately, you can&#8217;t update the results of a <code>JOIN</code>. How then to select the relevant rows?</p><p>Turns out it&#8217;s easier than I thought. You can still use the <code>WHERE ... IN</code> clause, you just specify all of the columns that satisfy the condition: <code>UPDATE table ... WHERE (key_column1, key_column2) IN (SELECT key_column1, key_column2 FROM ...)</code>.</p><p>I did not see any information about this functionality in the MySQL Reference Manual (<a
href="http://dev.mysql.com/doc/refman/5.0/en/any-in-some-subqueries.html">1</a>, <a
href="http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html">2</a>).</p> ]]></content:encoded> <wfw:commentRss>http://techlog.p2061.org/2008/10/07/sql-tricks-where-column-in-select/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Items Utility: Data Conversion Ready</title><link>http://techlog.p2061.org/2008/07/25/items-utility-data-conversion-ready/</link> <comments>http://techlog.p2061.org/2008/07/25/items-utility-data-conversion-ready/#comments</comments> <pubDate>Fri, 25 Jul 2008 14:54:04 +0000</pubDate> <dc:creator>bsweeney</dc:creator> <category><![CDATA[Adobe Illustrator]]></category> <category><![CDATA[MySQL]]></category> <category><![CDATA[Web Development]]></category> <guid
isPermaLink="false">http://techlog.p2061.org/?p=70</guid> <description><![CDATA[After creating a new structure for the current year&#8217;s piloting data there has been a bit of disconnect in development between the two data sets. There&#8217;s just not enough time to ensure that everything works across both data sets. There were basically two choices to moving forward: 1) construct a view of the new data [...]]]></description> <content:encoded><![CDATA[<p>After creating a new structure for the current year&#8217;s piloting data there has been a bit of disconnect in development between the two data sets. There&#8217;s just not enough time to ensure that everything works across both data sets. There were basically two choices to moving forward: 1) construct a view of the new data structure that mimics the old data structure; 2) port the old data structure to the new one and continue redevelopment of the scripts. I chose the latter, mainly because there are some improvements I&#8217;d like to make to the interface in the process.</p><p>I created a series of <a
href="http://techlog.p2061.org/wp-content/uploads/2008/08/convert-from-packet_item_records-to-packet_data.sql">SQL statements</a> to run in MySQL that will convert the data from the packet_item_records and miscon_packet_refs tables to the packet_students, packet_data, and miscon_packetdata_refs tables. After the conversion I updated any pages that referenced the old data structure. So far in testing the data seems to have converted perfectly.</p><p>Minus one issue. Multiple selections for the answer choice questions (A, B, C, D) from 2006 were recorded as a generic <em>Multiple</em> rather than <em>Y+NS</em>, <em>N+NS</em>, etc. This value is not represented in the updated data format or on the data entry forms or summary tables. Rather then spend too much time addressing this issue I&#8217;m going to leave these values empty for now. I don&#8217;t expect this to be a problem since the researchers are focused on data for the current pilot and field tests. Also, I&#8217;m keeping the old version of the piloting data and scripts that interact with it online in case it&#8217;s needed.</p> ]]></content:encoded> <wfw:commentRss>http://techlog.p2061.org/2008/07/25/items-utility-data-conversion-ready/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Expanding Search Terms for More Inclusive Results</title><link>http://techlog.p2061.org/2008/05/14/expanding-search-terms-for-more-inclusive-results/</link> <comments>http://techlog.p2061.org/2008/05/14/expanding-search-terms-for-more-inclusive-results/#comments</comments> <pubDate>Wed, 14 May 2008 16:54:11 +0000</pubDate> <dc:creator>bsweeney</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Web Development]]></category> <guid
isPermaLink="false">http://techlog.p2061.org/2008/05/14/expanding-search-terms-for-more-inclusive-results/</guid> <description><![CDATA[While working on the Benchmarks search I wanted to try and provide a feature I find useful on Google and other search engines: word form expansion (lemmatisation). A little research showed to me that this would require more work than we really should be spending on search functionality. Especially considering that the built-in MySQL full [...]]]></description> <content:encoded><![CDATA[<p>While working on the Benchmarks search I wanted to try and provide a feature I find useful on Google and other search engines: word form expansion (<a
href="http://en.wikipedia.org/wiki/Lemmatisation">lemmatisation</a>). A little research showed to me that this would require more work than we really should be spending on search functionality. Especially considering that the built-in MySQL full text search capability is sufficient for our needs. So I decided to focus on a feature that would still provide value but require little time: <a
href="http://en.wikipedia.org/wiki/Word_stem">word stem</a> expansion.</p><p><span
id="more-64"></span></p><p><strong>Purpose and Need</strong></p><p>As I mentioned, we&#8217;re using the <a
href="http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html">full text search</a> capability of MySQL as the core of our search functionality. By default, MySQL performs a natural language full text search. This mode has a few restrictions that can affect the results that are returned, but most notable for our purposes is that a word provided by the user must match exactly a word in the record. What this means is that records with a variation of the word (such as a plural when a singular was provided) will not be returned. For example, if you search for &#8220;atom,&#8221; MySQL will not return records that have &#8220;atoms&#8221; or &#8220;atomic&#8221; but not &#8220;atom.&#8221;</p><p>I&#8217;ve found the easiest way to address this limitation is by performing the search using the keywords as typed, but then adding on results that have matches to the stem of the keywords. By using these two full text search methods in conjunction we can get the best results for our user.</p><p><strong>Finding the Stem</strong></p><p>The hardest part of this whole process was determining a way to find the stem for a word. Initially I developed a simple function that stripped plurality from a word. Is was simplistic, but provided a good sample of how effective stemming could be. A little more research led me to a PHP extension that uses an established algorithm to determine a word stem. The extension is available from the PECL PHP library and is called &#8220;<a
href="http://pecl.php.net/package/stem">stem</a>.&#8221; Installation is simple. On *nix you first install the extension:</p><blockquote><p><code>sudo pecl install stem</code></p></blockquote><p>Next, update the php.ini file to enable the extension by adding the following line:</p><blockquote><p><code>extension=stem.so</code></p></blockquote><p>Finally, restart the web server for the new setting to take affect:</p><blockquote><p><code>sudo /etc/init.d/apachectl graceful</code></p></blockquote><p>On Windows you first download the dll from <span
style="text-decoration: line-through;">pecl4win.php.net </span>(PECL installation actually involves compiling the extension binary which is not quite as straightforward on Windows). Place the dll in your php/ext directory. Next, update the php.ini file to enable the extension by adding the following line:</p><blockquote><p><code>extension=stem.dll</code></p></blockquote><p>Finally, restart IIS for the settings to take affect.</p><p><strong>How to Use</strong></p><p>Performing a search with stem expansion using MySQL&#8217;s full text search functionality is actually quite easy. First we need to break the search terms up so that we can stem them. To do this we need to isolate each word in the search phrase. We can do this by splitting the search phrase into an array. It&#8217;s impossible to know exactly what the user will type, so we can be greedy and use something like:</p><blockquote><p><code>$araKeys = preg_split('/\W/', $strSearch);</code></p></blockquote><p>Then we need to modify each keyword so that we have its stem:</p><blockquote><p><code>$araKeys = array_map('stem', $araKeys );</code></p></blockquote><p>Recombine the keywords into a new boolean search phrase:</p><blockquote><p><code>$strSearchBool = join('* ', $keysArray) . '*'</code></p></blockquote><p>Finally, we combine the original natural language search with a boolean mode search:</p><blockquote><p><code>MATCH(fulltext_index_columns) AGAINST ('$strSearch') OR MATCH(fulltext_index_columns) AGAINST ('$strSearchBool' IN BOOLEAN MODE)</code></p></blockquote><p>Order the results by the sum of the relevance values for the full text searches and you&#8217;re done:</p><blockquote><p><code>ORDER BY (MATCH(fulltext_index_columns) AGAINST ('$strSearch')) + (MATCH(fulltext_index_columns) AGAINST ('$strSearchBool' IN BOOLEAN MODE)) DESC<br
/> </code></p></blockquote><p>The two combined provides a good sense of how well a result matches. Records that match the entered search terms exactly will bubble to the top of the list since they match on both the natural language and boolean searches. Records that match only on the stem-based boolean search will come next, and the more words they match the higher in this secondary list they will be. These stem-based matches would not be returned by the natural language search since the exact search terms were not present in the records.</p><p><strong>Future Development</strong></p><p>MySQL has stated a desire to enhance full text searching with stem and proximity information. The implementation of these features will negate the need for this to be done via the hack described above. At that point this extra code should be removed, though I doubt it will cause problems with the search results if left in place.</p> ]]></content:encoded> <wfw:commentRss>http://techlog.p2061.org/2008/05/14/expanding-search-terms-for-more-inclusive-results/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Best Practices for Setting MySQL Server Runtime Parameters</title><link>http://techlog.p2061.org/2008/05/07/optimizing-mysql-server-runtime-parameters/</link> <comments>http://techlog.p2061.org/2008/05/07/optimizing-mysql-server-runtime-parameters/#comments</comments> <pubDate>Wed, 07 May 2008 18:55:25 +0000</pubDate> <dc:creator>bsweeney</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[System Administration]]></category> <guid
isPermaLink="false">http://techlog.p2061.org/2008/05/07/optimizing-mysql-server-runtime-parameters/</guid> <description><![CDATA[Since we&#8217;ll be exposing MySQL to significantly more traffic (due mainly to the transition to a database-driven version of Benchmarks Online [dbBOL]) I decided to spend some time optimizing the server&#8217;s settings. There are a number of settings that can be tweaked to improve performance. I based my decisions on the information available from the [...]]]></description> <content:encoded><![CDATA[<p>Since we&#8217;ll be exposing MySQL to significantly more traffic (due mainly to the transition to a database-driven version of<cite>Benchmarks Online</cite> [dbBOL]) I decided to spend some time optimizing the server&#8217;s settings. There are a number of settings that can be tweaked to improve performance. I based my decisions on the information available from the references cited and the performance statistics reported by MySQL (SQL <code>SHOW VARIABLES</code> or use PHPMyAdmin). MySQL has been running for 131 days as of the writing of this post (<a
href="http://techlog.p2061.org/nonwp-files/server_status_080317.htm">see cached copy</a> of the runtime stats), so I expect the data will be a fairly good indication of the performance of MySQL under its current usage. Unfortunately, I expect the usage pattern to change significantly once dbBOL is released. As a result some of the settings used will be based on expected usage patterns. At specific intervals after dbBOL is released we should examine the performance of MySQL based on the runtime stats to determine if additional tweaking needs to be performed. I recommend the following schedule: 1 week, 1 month, 3 months, then every 6 months.</p><p><span
id="more-51"></span></p><p><strong>MyISAM Recovery</strong></p><p>MyISAM is a nice format for speed and has support for functionality not available in other MySQL storage engines (such as full text search). Unfortunately MyISAM is not nearly as robust as InnoDB. Since the data files are dealt with directly sans transactions a system crash can cause table corruption and loss of data (particularly is an <code>INSERT</code>/<code>UPDATE</code> operation were in progress). To ensure that the tables have not been corrupted at any time we can set <code>myisam-recover=BACKUP,FORCE</code>. This will tell MySQL to check a MyISAM table when it is opened, repair it if necessary, and make a backup of the table.</p><p>There are some drawbacks with this setting. First, if a row is corrupted the data from that row could be lost. That&#8217;s why we use the <code>BACKUP</code> option. Also, there can be a performance hit due to recovery operations, particularly if a large number of tables have to be repaired simultaneously. Not to mention that the recovery check is done every time a table is opened.</p><p>Another method of checking the MyISAM tables we should consider is a cron job that checks the tables outside of MySQL. This would give us the benefit of automated repair (or at least notification) while mitigating possible performance bottlenecks.</p><p>References:</p><ul><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/server-options.html#option_mysqld_myisam-recover"> MySQL Reference Manual: 5.1.2. Command Options</a></li><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#option_mysqld_tmp_table_size">MySQL Reference Manual: 5.1.3. System Variables</a></li><li><a
href="http://www.mysqlperformanceblog.com/2006/06/17/using-myisam-in-production/">MySQL Performance Blog: Using MyISAM in production</a></li><li><a
href="http://www.mysqlperformanceblog.com/2006/07/30/mysql-crash-recovery/">MySQL Performance Blog: MySQL Crash Recovery</a></li></ul><p><strong>Thread Cache</strong></p><p>MySQL assigns a thread to each connection made by a client. Thread creation/destruction can be a relatively expensive process, but MySQL gets around this by implementing thread caching. Thread caching allows MySQL to reuse a thread once a connection is finished with it. A thread is not destroyed unless the number of active threads exceeds the thread cache limit. The thread cache does not have to be large enough to handle all simultaneous connections, particularly since maintaining a thread uses up system resources. The cache should be large enough, however, such that the number of threads created is small. Check the Threads_created server status variable.</p><p>We currently do not have thread caching enabled. Our threads created is at 60,000, which is extremely high (~460 per day). Unless you set up persistent connections to MySQL using the <code>pconnect()</code> function PHP will open/close a connection each time a web page is loaded. I&#8217;m going to go with a value of 20. Assuming maximum concurrent connection could reach 25 this provides plenty of cached connections for average usage. If the number of threads created does not budge past the cache limit we should consider lowering the value somewhat to free up resources.</p><p>For an hint of how important thread caching is, see <a
href="http://jeremy.zawodny.com/blog/archives/000173.html">MySQL, Linux, and Thread Caching</a> and <a
href="http://www.epigroove.com/posts/63/optimize_mysql_the_thread_cache">Optimize MySQL: The Thread Cache</a>.</p><p>References:</p><ul><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/connection-threads.html">MySQL Reference Manual: 7.5.7. How MySQL Uses Threads for Client Connections</a></li><li><a
href="http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server-after-installation/">MySQL Performance Blog: What to tune in MySQL Server after installation</a></li></ul><p><strong>Table Cache</strong></p><p>Opening a table can be a slow process as data descriptors are created and file headers are modified. To mitigate this MySQL uses a file-based table cache that maintains a table in an open state for future connections. A unique entry in the table cache is required for each concurrent access to a table (multiple users or multiple accesses by a single user in a query). Every time a table is opened an unused table cache entry for that table is sought. If none is found a new one is created. Once the table cache reaches the limit specified by the <code>table_cache</code> variable MySQL has to close old cached connections before opening new ones, adding even more time to table access. MySQL recommends sizing the table cache so that it can handle the largest number of concurrent connections multiplied by the largest number of tables accessed by a single query. This is at the high end. You can start lower and watch <code>opened_tables</code> to see if the table cache is constantly swapping out tables. The faster <code>opened_tables</code> rises the more urgently the table cache needs to be increased.</p><p>One caveat to consider when setting the table cache is the per-process file pointer limit. Each cache entry is associated with MySQL. If the number of files held open by MySQL exceeds the limit allowed by the operating system no further files can be opened. MySQL does not fail gracefully in this situation and may, according to the documentation, &#8220;refuse connections, fail to perform queries, and be very unreliable.&#8221; You can find the file usage limit by issuing the following command <code>cat /proc/sys/fs/file-max</code>. It&#8217;s very unlikely we&#8217;ll have a problem; the current value indicated by this command is 50569. But the results of going over this limit appear to be fairly severe for MySQL, so it&#8217;s a good idea to check.</p><p>The current table cache of is set to 160 and is full, but the value of opened tables is rising slowly. Still, our maximum concurrent connections has already hit ten, so I believe we could easily see the table cache get overwhelmed once the database is exposed to a larger traffic base. If we assume maximum concurrent connections of 25 and a crazy join of 10 tables then we&#8217;re looking at a table cache of around 250. I&#8217;ll start with this number and watch the opened tables stat to see if the cache needs to go higher or can be lowered.</p><p>References:</p><ul><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/table-cache.html">MySQL Reference Manual: 7.4.8. How MySQL Opens and Closes Tables</a></li><li><a
href="http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server-after-installation/">MySQL Performance Blog: What to tune in MySQL Server after installation</a></li><li><a
href="http://www.databasejournal.com/features/mysql/article.php/3367871/Optimizing-the-mysqld-variables.htm">Database Journal: Optimizing the mysqld variables</a></li></ul><p><strong>Temporary Tables</strong></p><p>Temporary tables may be used by MySQL when performing queries. By default these tables are created in memory. However, there are two situations in which a temporary table will be written to disk, resulting in a bit of a performance hit: when a temporary table grows beyond the maximum allowed; and when a condition exists that prevents the use of a temporary table. The former situation is one determined by the <code>tmp_table_size</code>/<code>max_heap_table_size</code> parameters. The latter is determined by table and query structure. <code>tmp_table_size</code> is specific to temporary tables while <code>max_heap_table_size</code> applies to all memory tables, so make sure that <code>max_heap_table_size</code> is at least as large as <code>tmp_table_size</code>.</p><p>The allowable size of temporary tables should be large enough to avoid writing to disk where possible, but small enough that memory is not eaten up. There is no provision to limit the number of temporary tables stored in memory. If there are many simultaneous connections and each connection is working with a large temporary table memory could be filled rather quickly.</p><p>You can determine whether or not your temporary tables are being created in memory by looking at the number of temporary tables that had to be written to disk (<code>Created_tmp_disk_tables</code>). Ours is hovering around 50% of the total number of temporary tables (<code>Created_tmp_tables</code>), but this isn&#8217;t enough information to make a decision about the optimal setting for <code>tmp_table_size</code>. What we don&#8217;t know is the reason a table is written to disk. That&#8217;s something that can only be determined using the <code>EXPLAIN</code> statement.</p><p>Since the number of disk-based temporary tables is relatively high I&#8217;m going to increase the maximum size allowed for memory-based tables and see if that improves things.</p><p>References:</p><ul><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#option_mysqld_tmp_table_size">MySQL Reference Manual: 5.1.3. System Variables</a></li><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/server-status-variables.html#option_mysqld_Created_tmp_disk_tables">MySQL Reference Manual: 5.1.5. Status Variables</a></li><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/internal-temporary-tables.html">MySQL Reference Manual: 7.5.9. How MySQL Uses Internal Temporary Tables</a></li><li><a
href="http://www.databasejournal.com/features/mysql/article.php/3367871/Optimizing-the-mysqld-variables.htm">Database Journal: Optimizing the mysqld variables</a></li></ul><p><strong>Query Cache</strong></p><p>For SELECT queries, the speed of the response can be affected by factors such as query structure and which columns are indexed. MySQL is able to provide fast results for often-run queries by storing the results in the query cache. The first time a query is run the query and its result set are stored in the query cache. Subsequent runs of the exact same query will pull the results from the cache (so long as the cached entry is available). There are some qualifications for the query cache to be used successful. First, a query must match in a binary manner in order for MySQL to use a cached query. This means a query must match character for character in a case-sensitive way with the previous run. Second, the query results must not exceed a defined size (1MB by default) or it will not be cached.</p><p>To enable the query cache set <code>query-cache-type = 1</code> and give <code>query_cache_size</code> a value. The best size of the query cache is a guessing game. I&#8217;m starting with a value of 32M. Though we&#8217;re likely to see little performance improvement on the web-based applications due to constant table updates (which invalidates any cached results for that table) we should see decent performance improvement for more static tables such as those used to serve dbBOL. As a result, judging the efficiency of the cache based on the usage data provided by MySQL will be somewhat difficult. Still, I would expect to see a relatively high value for <code>Qcache_hits</code> when compared to <code>Qcache_inserts</code> and a low value for <code>Qcache_lowmem_prunes</code>. It&#8217;s also important to keep an eye on <code>Qcache_free_blocks</code> in order to ensure the cache memory is not fragmented. This number should remain low and can be improved temporarily by issuing a <code>FLUSH QUERY CACHE</code> statement, which will &#8220;defragment&#8221; the query cache.</p><p>One thing to keep in mind is that any cached query will be dropped if the table it references is updated. Tables that are updated often should include the <code>SQL_NO_CACHE</code> attribute in any SELECT queries to prevent caching. This will help prevent the extra overhead of storing and dropping queries from the cache when those caches can rarely be reused.</p><p>References:</p><ul><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/query-cache.html">MySQL Reference Manual: 7.5.4. The MySQL Query Cache</a></li><li><a
href="http://dev.mysql.com/tech-resources/articles/mysql-query-cache.html" class="broken_link">MySQL: A Practical Look at the MySQL Query Cache</a></li><li><a
href="http://www.databasejournal.com/features/mysql/article.php/10897_3110171_1/MySQLs-Query-Cache.htm">Database Journal: MySQL&#8217;s Query Cache</a></li><li><a
href="http://jayant7k.blogspot.com/2007/07/mysql-query-cache.html">Whatever&#8230;.: mysql query cache</a></li></ul><p><strong>Key Buffer</strong></p><p>MySQL says this is one of the most important performance tuning variables and recommends allocating as much memory as possible. However, since the key buffer is stored in RAM a setting should be used that (in consideration with other settings) won&#8217;t cause the server to page memory. MySQL also recommends that the <code>key_reads</code>/<code>key_read_requests</code> be less than 0.01.</p><p>The MySQL Performance Blog recommends up to 40% of your system memory, taking into account the size of the MyISAM table indexes and available memory.</p><p>Currently the setting for this parameter is 16M and our <code>key_reads</code>/<code>key_read_requests</code> are very low (0.0002). So right now we seem to be doing great in regard to this value, but since MySQL recommends a high value I&#8217;m going to increase this to 24M or about 4.7% of system memory. Though this value is below the roughly 58M that the table indexes add up to, the maximum portion of the key buffer that has been used at any one time so far is only about 70% (based on a block size of 1M and <code>Key_blocks_used</code> showing 11K, meaning roughly 11M of 16M in the current setup).</p><p>Due to how MySQL uses the indexes, we should be O.K. with a key buffer size smaller than the sum of the indexes. As I understand it, MySQL divides indexes into blocks which allows MySQL to only access the part of an index it needs. Only used portions of a particular index need to be stored in the key buffer. Since some of the tables in the database are rarely (if ever) used their indexes won&#8217;t add to the overall key buffer usage.</p><p><em>Special note:</em> some tables have rather large indexes. These tables should be reviewed to determine if any optimizations to the table structure can be made.</p><p>References:</p><ul><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#option_mysqld_key_buffer_size">MySQL Reference Manual: 5.1.3. System Variables</a></li><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/myisam-key-cache.html">MySQL Reference Manual: 7.4.6. The MyISAM Key Cache</a></li><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/server-parameters.html">MySQL Reference Manual: 7.5.2. Tuning Server Parameters</a></li><li><a
href="http://www.mysqlperformanceblog.com/2006/09/29/what-to-tune-in-mysql-server-after-installation/">MySQL Performance Blog: What to tune in MySQL Server after installation</a></li><li><a
href="http://www.databasejournal.com/features/mysql/article.php/3367871/Optimizing-the-mysqld-variables.htm">Database Journal: Optimizing the mysqld variables</a></li></ul><p><strong>Sort Buffer</strong></p><p>The sort buffer is used whenever ORDER BY or GROUP BY is used in a query. If the amount of memory required to perform an operation of this type exceeds the value of <code>sort_buffer_size</code> MySQL has to sort the current working set, write the data out to disc, and start another working set. So not only do you have the problem of sorting parts of the result set separately, but then those groupings have to be combined on disc and sorted. Conceivably, then, a larger value would be beneficial. You can see how often a sort buffer has to be written out to disc and combined with additional buffered data by looking at the <code>Sort_merge_passes</code> status variable.</p><p>The sort buffer is a per-connection setting, meaning that each connection can allocate the amount specified by this value. As a result, care should be taken when setting this value in order to avoid eating up too much memory. Also, the MySQL Performance Blog has benchmarks showing a larger sort buffer actually hurting performance. With all this in mind it may be wise to use a relatively low value in the server settings and specify a larger value when necessary for a specific connection. Also, it may be advisable to perform some testing in various scenarios to see if there is an optimal minimum to cover most situations.</p><p>Still, MySQL recommends using a larger value to help improve sorting. Our current value was 512K. Our merge passes appear to be rising steadily (though not severely). So for now I&#8217;m doubling the value.</p><p>References:</p><ul><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#option_mysqld_sort_buffer_size">MySQL Reference Manual: 5.1.3. System Variables</a></li><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/server-status-variables.html#option_mysqld_Sort_merge_passes">MySQL Reference Manual: 5.1.5. Status Variables</a></li><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html">MySQL Reference Manual: 7.2.11. ORDER BY Optimization</a></li><li><a
href="http://www.mysqlperformanceblog.com/2007/08/18/how-fast-can-you-sort-data-with-mysql/">MySQL Performance Blog: How fast can you sort data with MySQL?</a></li><li><a
href="http://www.mysqlperformanceblog.com/2006/06/06/are-larger-buffers-always-better/">MySQL Performance Blog: Are larger buffers always better?</a></li><li><a
href="http://www.databasejournal.com/features/mysql/article.php/3367871/Optimizing-the-mysqld-variables.htm">Database Journal: Optimizing the mysqld variables</a></li></ul><p><strong>Read Buffers</strong></p><p>MySQL uses read buffers when accessing table data. There are two settings to pay attention to here: <code>read_buffer_size</code> and <code>read_rnd_buffer_size</code>. MySQL allocates <code>read_buffer_size</code> when a sequential scan is performed. A sequential scan is when every row in a table is read and typically would be done when an index can&#8217;t be used to satisfy a query. MySQL allocates <code>read_rnd_buffer_size</code> when tables rows are read based on a key sort.</p><p>As with the sort buffer, the read buffers are a per-connection setting. So setting this value with consideration of our available memory is important. Plus, the MySQL Performance Blog has found some performance issues with larger values for these settings, similar to the issues with the sort buffer. Once again these are variables that may be best increased as needed. And again, testing should be done to find an optimal minimum.</p><p>Since these settings can show something of a benefit we want to increase the value if possible. Until further testing can be done on our system, however, I&#8217;ll keep these values below the theorized threshold of decreasing returns, 256K (at least until further testing and optimization can be done with our own system).</p><p>References:</p><ul><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#option_mysqld_read_buffer_size">MySQL Reference Manual: 5.1.3. System Variables</a></li><li><a
href="http://dev.mysql.com/doc/refman/5.0/en/server-parameters.html">MySQL Reference Manual: 7.5.2. Tuning Server Parameters</a></li><li><a
href="http://www.mysqlperformanceblog.com/2007/09/17/mysql-what-read_buffer_size-value-is-optimal/">MySQL Performance Blog: MySQL: what read_buffer_size value is optimal?</a></li><li><a
href="http://www.mysqlperformanceblog.com/2006/06/06/are-larger-buffers-always-better/">MySQL Performance Blog: Are larger buffers always better?</a></li><li><a
href="http://www.mysqlperformanceblog.com/2007/07/24/what-exactly-is-read_rnd_buffer_size/">MySQL Performance Blog: What exactly is read_rnd_buffer_size?</a></li><li><a
href="http://www.mysqlperformanceblog.com/2007/09/12/read-buffers-mmap-malloc-and-mysql-performance/">MySQL Performance Blog: Read Buffers, mmap, malloc and MySQL Performance</a></li><li><a
href="http://inaugust.com/post/14">In August Productions: Read Buffer performance hit</a></li><li><a
href="http://www.databasejournal.com/features/mysql/article.php/3367871/Optimizing-the-mysqld-variables.htm">Database Journal: Optimizing the mysqld variables</a></li></ul><p><strong>InnoDB</strong></p><p>The MySQL Performance Blog recommends a number of settings for enhancement of InnoDB performance. After much consideration, however, I believe it may be best if we forgo usage of the InnoDB storage engine where appropriate. I have a few reasons for this opinion</p><ol><li>InnoDB tables are more resource intensive due to their use of transactions.</li><li>Fulltext indexing, a feature of MySQL that we have come to depend on for a number of applications, is not currently available for InnoDB tables.</li><li>Our current applications do not generally require the added safety of a transactional database.</li></ol><p>If we do decide in the future to implement InnoDB for a future application (such as an online ordering system) we should revisit the optimization settings.</p><p>To ensure that tables are MyISAM by default I have set <code>default-storage-engine = MyISAM</code>. This can be overrode by specifying the table engine when creating a new table or by altering a table.</p><p><strong>Fin</strong></p><p>Once settings changes have been made to /etc/my.cnf restart the server and check the server variables (<code>SHOW GLOBAL STATUS</code> or use PHPMyAdmin) to ensure all settings have been implemented correctly.</p><p>Also, see my <a
href="http://techlog.p2061.org/2007/07/13/optimizing-mysql/">earlier post on optimization</a>.</p> ]]></content:encoded> <wfw:commentRss>http://techlog.p2061.org/2008/05/07/optimizing-mysql-server-runtime-parameters/feed/</wfw:commentRss> <slash:comments>4</slash:comments> </item> <item><title>Misconceptions misnumbering</title><link>http://techlog.p2061.org/2008/02/11/misconceptions-misnumbering/</link> <comments>http://techlog.p2061.org/2008/02/11/misconceptions-misnumbering/#comments</comments> <pubDate>Mon, 11 Feb 2008 18:57:05 +0000</pubDate> <dc:creator>bwalker</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[items]]></category> <category><![CDATA[miscon]]></category> <category><![CDATA[misconceptions]]></category> <category><![CDATA[miscons]]></category> <category><![CDATA[numbering]]></category> <guid
isPermaLink="false">http://techlog.p2061.org/2008/02/11/misconceptions-misnumbering/</guid> <description><![CDATA[Jill is working on a new topic ( Processes that shape the earth/Plate Tectonics Version II (PT)) which shares a number of misconceptions with another topic (Earth Science: Processes that shape the Earth / Plate Tectonics (EP)). Problem: She changed the topic of those misconceptions believing it would be available to both topics. Once she [...]]]></description> <content:encoded><![CDATA[<p>Jill is working on a new topic (</p><p>Processes that shape the earth/Plate Tectonics Version II (PT)) which shares a number of misconceptions with another topic (Earth Science: Processes that shape the Earth / Plate Tectonics (EP)).</p><p>Problem: She changed the topic of  those misconceptions believing it would be available to both topics.  Once she realized this was not the case, she changed the topic back, but the numbering was off.</p><p>Solution: She provided me a list of which misconceptions were out of sync.  Because adding a misconception involves updating multiple tables I actually had to add the misconceptions through the Item interface and then change the numbering on the backend.</p><p>Conclusion: The conclusion is that the conclusion is pretty obvious.  This functionality needs to be revised.  Changing the topic of a misconception has considerable consequences throughout the Items utility, so I think it may be necessary to add an additional step to this process.  For example, have the current topic displayed along with a check box and a disabled/hidden topic menu.  Then use the checkbox to enable/disable the menu and possibly some kind of textual warning (&#8220;Changing this is likely to break something.&#8221;).</p><p>Another note is that the &#8216;code&#8217; column denoting the numbering sequence is not a unique column so we could have the numbering be editable on the interface.  Although this could have some duplication complications.</p><p>I also found it strange that when submitting a new misconception, there is no notification and you are not redirected back to the miscon list.  I found out the hard way that once you submit a misconception you are essentially in edit mode (not Add New Miscon anymore) and any changes made are being made to the record you just added.  It wasn&#8217;t obvious to me the difference between Add and Edit mode.</p> ]]></content:encoded> <wfw:commentRss>http://techlog.p2061.org/2008/02/11/misconceptions-misnumbering/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Updates to field test registrant_list_demo</title><link>http://techlog.p2061.org/2008/02/11/updates-to-field-test-registrant_list_demo/</link> <comments>http://techlog.p2061.org/2008/02/11/updates-to-field-test-registrant_list_demo/#comments</comments> <pubDate>Mon, 11 Feb 2008 18:33:02 +0000</pubDate> <dc:creator>bwalker</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <guid
isPermaLink="false">http://techlog.p2061.org/2008/02/11/updates-to-field-test-registrant_list_demo/</guid> <description><![CDATA[As I was meddling with registrant_list_demo.php I found that the demographics were not showing up for any of my test cases.  I was under the mistaken impression this data was obtained from an external server, but it is actually taken from a data dump from the nces stored on our server in a database called &#8216;demographics&#8217; [...]]]></description> <content:encoded><![CDATA[<p>As I was meddling with registrant_list_demo.php I found that the demographics were not showing up for any of my test cases.  I was under the mistaken impression this data was obtained from an external server, but it is actually taken from a data dump from the nces stored on our server in a database called &#8216;demographics&#8217; (go figure).  The demographics data appears to be sorted by zip code.  I am surmising that this data dump is requested from nces after the registration process is complete and an updated list of zip codes has been generated. </p><p>I&#8217;m sure Mr. Sweeney can provide details of this request procedure upon his return.  The demographics script is working fine, but the demographics data is most likely out if date.  Cari indicated the demographics data will not be needed for a few weeks.</p> ]]></content:encoded> <wfw:commentRss>http://techlog.p2061.org/2008/02/11/updates-to-field-test-registrant_list_demo/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Updates to field test registrant_list</title><link>http://techlog.p2061.org/2008/02/11/updates-to-field-test-registrant_list/</link> <comments>http://techlog.p2061.org/2008/02/11/updates-to-field-test-registrant_list/#comments</comments> <pubDate>Mon, 11 Feb 2008 18:23:39 +0000</pubDate> <dc:creator>bwalker</dc:creator> <category><![CDATA[MySQL]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[field]]></category> <category><![CDATA[field test registration]]></category> <category><![CDATA[registrant list]]></category> <category><![CDATA[registrant_list]]></category> <category><![CDATA[registrant_list.php]]></category> <category><![CDATA[registration]]></category> <guid
isPermaLink="false">http://techlog.p2061.org/2008/02/11/updates-to-field-test-registrant_list/</guid> <description><![CDATA[When I first opened up the register dir I found register.php, review.php and review.v1.php.  Based on script and notes in the script the registration and review registration processes were consolidatedby Mr. Sweeney in register.php, but perhaps at one point they were separate.  review.php and review.v1.php turned out to be the registrant listing scripts.  This names [...]]]></description> <content:encoded><![CDATA[<p>When I first opened up the register dir I found register.php, review.php and review.v1.php.  Based on script and notes in the script the registration and review registration processes were consolidatedby Mr. Sweeney in register.php, but perhaps at one point they were separate.  review.php and review.v1.php turned out to be the registrant listing scripts. </p><p>This names were confusing so I renamed them to registrant_list.php and registrant_list_demo.php (demographics).</p><p>I added a filter (by year) to limit output results.  However it is not technically filtering by year.  There was already a date limit written into the existing query (2007-04-27, I think) which I used as the start range marker for 2007.  The start range for 2008 is 2008-01-01.  The messy part is that everything prior to 2007-04-27 is marked as 2006 in the filter when in fact the records only go back to 2007-04-17.  I expect to be working on this script again in the near future (see &#8220;Updates to field test registrant_list_demo&#8221;) at which point I will probably change the filter to just &#8216;Prior&#8217;.</p> ]]></content:encoded> <wfw:commentRss>http://techlog.p2061.org/2008/02/11/updates-to-field-test-registrant_list/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> </channel> </rss>
