<?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>drittenormalform *Beta* &#187; Niglichkeiten</title>
	<atom:link href="http://drittenormalform.de/wordpress/category/niglichkeiten/feed/" rel="self" type="application/rss+xml" />
	<link>http://drittenormalform.de/wordpress</link>
	<description>Datenbank Merkzettel und Sammlung rund um Storagethemen</description>
	<lastBuildDate>Mon, 05 Oct 2009 10:10:57 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Eine Queue leerräumen mit SELECT FOR UPDATE</title>
		<link>http://drittenormalform.de/wordpress/2009/07/17/eine-queue-leerraumen-mit-select-for-update/</link>
		<comments>http://drittenormalform.de/wordpress/2009/07/17/eine-queue-leerraumen-mit-select-for-update/#comments</comments>
		<pubDate>Fri, 17 Jul 2009 20:18:17 +0000</pubDate>
		<dc:creator>Thomas</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Niglichkeiten]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[LIMIT]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Select]]></category>
		<category><![CDATA[select for update]]></category>
		<category><![CDATA[tablelock]]></category>

		<guid isPermaLink="false">http://drittenormalform.de/wordpress/?p=91</guid>
		<description><![CDATA[Man braucht es nicht oft aber ab und an ist ein blockierender SELECT ein sogenannter SELECT FOR UPDATE notwendig, z.B. bei dem Klassiker:
Gegeben ist eine Datenbankqueue von der sich viele Jobs bedienen, nun soll sichergestellt werden das Daten nicht mehrfach aus dieser gelesen und z.B. gelöscht werden, wie geht man vor.
Im Gegensatz zu Oracle kennt [...]]]></description>
			<content:encoded><![CDATA[<p>Man braucht es nicht oft aber ab und an ist ein blockierender SELECT ein sogenannter SELECT FOR UPDATE notwendig, z.B. bei dem Klassiker:<br />
Gegeben ist eine Datenbankqueue von der sich viele Jobs bedienen, nun soll sichergestellt werden das Daten nicht mehrfach aus dieser gelesen und z.B. gelöscht werden, wie geht man vor.<br />
Im Gegensatz zu Oracle kennt MySQL kein RETURNING sonst wäre ein DELETE mit einem rowcount und einem RETURNING das Mittel der Wahl, irgendwas so in der Art:</p>
<pre><code>DELETE FROM TABLE WHERE rownum &lt; 100 RETURNING id;</code></code></pre>
<p>In MySQL müssen wir das in eine Transaktion verpacken und erst die Daten selektieren und dann können wir sie löschen (und genau dafür brauche ich nun eine <a href="http://drittenormalform.de/wordpress/2009/07/17/test-tabellen-erstellen-per-procedure/">gefüllte Testdatenbank</a> aus meinem letzten Posting):</p>
<pre><code>BEGIN;
SELECT id,f1,f2 FROM strintab ORDER BY ts ASC LIMIT 100;
#mach was mit den Results
DELETE FROM stringtab WHERE id in (..vermutlich alle abgeholten....);
COMMIT;</code></pre>
<p>Damit hole ich exklusiv die ersten 100 Zeilen aus der DB und keiner kann auf die Daten zugreifen.<br />
Kurz ausprobiert und tatsächlich niemand kann zugreifen weder auf die 100 records noch auf die anderen rows&#8230;</p>
<p>Wieso?<br />
MySQL sperrt alle Zeilen über die sei zum zusammenstellen des Ergebnisses &#8220;drüber streicht&#8221;.<br />
Will heißen so lange MySQL einen full table scan machen muss, sind alle records gesperrt sobald ein Index im Spiel ist und nur ein index range scan notwendig wird ist dieser Bereich gesperrt (<a href="http://www.tbee.de/mysql/mysql_performance/#(16)">mehr zu Explain</a>).<br />
Und auch ein LIMIT wird berücksichtigt also tatsächlich nur 100 Zeilen gesperrt wenn ich das Ergebnis mit einem LIMIT einschränke.</p>
<p>Also dann, legen wir einen Index an:</p>
<pre><code>ALTER TABLE `test`.`stringtab`
 DROP INDEX `Index_timestamp`,
 ADD INDEX `Idx_stringtab_ts` USING BTREE(`ts`);</code></pre>
<p>Und führen auf je einer Connection obiges Statement aus und wundern uns zuerst wieso eins davon wieder in einem Lock wait hängt (auch ein LIMIT 10,10 hilft nix)<br />
Wenn man weiß das MySQL LIMIT immer bei 0 anfängt wird es klarer, die gesperrte Range startet immer bei 0 das Offset ist nur für die Ausgabe relevant.<br />
Abhilfe schafft eine Änderung des Sortierkriteriums z.B.:  DESC oder eine andere WHERE clause.<br />
Alternativ und eher die empfehlenswerte Variante, im aufrufenden Programm sich die zu bearbeitenden  resultsets merken und dann sofort auf der DB löschen und die Transaktion mit COMMIT  freigeben und dabei halt das Risiko der Persistenz im Programm tragen.</p>
<p>Fassen wir zusammen:</p>
<ul>
<li><strong>ohne</strong> Index immer ein lock auf die <strong>ganze</strong> Tabelle</li>
<li>mit Index immer ein lock auf alle rows die durch die WHERE/ORDER BY clause eingeschränkt werden</li>
<li>LIMIT wird berücksichtigt und sorgt für weniger row locks</li>
<li>EXPLAIN ist wichtig</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://drittenormalform.de/wordpress/2009/07/17/eine-queue-leerraumen-mit-select-for-update/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Update mit JOIN &#8211; Syntaxstolperei</title>
		<link>http://drittenormalform.de/wordpress/2009/07/09/update-mit-join-syntaxstolperei/</link>
		<comments>http://drittenormalform.de/wordpress/2009/07/09/update-mit-join-syntaxstolperei/#comments</comments>
		<pubDate>Thu, 09 Jul 2009 14:26:25 +0000</pubDate>
		<dc:creator>Thomas</dc:creator>
				<category><![CDATA[Niglichkeiten]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[JOIN]]></category>
		<category><![CDATA[UPDATE]]></category>

		<guid isPermaLink="false">http://drittenormalform.de/wordpress/?p=48</guid>
		<description><![CDATA[Heute kurz festgehalten worüber SQL Neulinge auch des öfteren mal stolpern:
Ich will in einer Tabelle Felder mit Werten aus einer anderen Tabelle füllen wenn die ID aus der Quelltabelle identisch ist mit der Ziel Tabelle.
Dann wird erst einmal losgewerkelt und sich gewundet warum ein
UPDATE ziel SET ziel.wert = quell.wert FROM quelle WHERE ziel.id = quell.id;

nicht [...]]]></description>
			<content:encoded><![CDATA[<p>Heute kurz festgehalten worüber SQL Neulinge auch des öfteren mal stolpern:</p>
<p>Ich will in einer Tabelle Felder mit Werten aus einer anderen Tabelle füllen wenn die ID aus der Quelltabelle identisch ist mit der Ziel Tabelle.</p>
<p>Dann wird erst einmal losgewerkelt und sich gewundet warum ein</p>
<blockquote><p>UPDATE ziel SET ziel.wert = quell.wert FROM quelle WHERE ziel.id = quell.id;</p>
</blockquote>
<p>nicht funktioniert.<br />
Ein UPDATE kennt halt kein FROM und so wird das dann auch was:</p>
<blockquote><p>UPDATE ziel,quelle  SET ziel.wert = quell.wert WHERE ziel.id = quell.id;</p>
</blockquote>
<p>Selbstverständlich geht das auch mit allen LEFT/RIGHT und was auch immer für JOINs</p>
]]></content:encoded>
			<wfw:commentRss>http://drittenormalform.de/wordpress/2009/07/09/update-mit-join-syntaxstolperei/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Autoincrement Verhalten in MySQL</title>
		<link>http://drittenormalform.de/wordpress/2009/07/08/autoincrement-verhalten-in-mysql/</link>
		<comments>http://drittenormalform.de/wordpress/2009/07/08/autoincrement-verhalten-in-mysql/#comments</comments>
		<pubDate>Wed, 08 Jul 2009 15:20:29 +0000</pubDate>
		<dc:creator>Thomas</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Niglichkeiten]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Autoincrement]]></category>
		<category><![CDATA[Verhalten]]></category>

		<guid isPermaLink="false">http://drittenormalform.de/wordpress/?p=13</guid>
		<description><![CDATA[Immer wieder mal stolpere ich über die Frage wie verhält sich das MySQL Autoincrement bei bereits belegten PK IDs.
CREATE TABLE `testab`
(
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1;
INSERT INTO `testab` (`name`) VALUES (&#8217;blub&#8217;);
INSERT INTO `testab` (`id`,`name`) VALUES  (9,&#8217;9bsdwldub&#8217;);
INSERT INTO `testab` (,`name`) VALUES (&#8217;blub&#8217;); (&#8217;2&#8242;blub&#8217;);
Der letzte insert hat den PK 10 [...]]]></description>
			<content:encoded><![CDATA[<p>Immer wieder mal stolpere ich über die Frage wie verhält sich das MySQL Autoincrement bei bereits belegten PK IDs.</p>
<blockquote><p>CREATE TABLE `testab`<br />
(<br />
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,<br />
`name` varchar(45) NOT NULL,<br />
PRIMARY KEY (`id`)<br />
) ENGINE=InnoDB AUTO_INCREMENT=1;</p>
<p>INSERT INTO `testab` (`name`) VALUES (&#8217;blub&#8217;);</p>
<p>INSERT INTO `testab` (`id`,`name`) VALUES  (9,&#8217;9bsdwldub&#8217;);</p>
<p>INSERT INTO `testab` (,`name`) VALUES (&#8217;blub&#8217;); (&#8217;2&#8242;blub&#8217;);</p></blockquote>
<p>Der letzte <em>insert</em> hat den PK 10 d.h. MySQL (wie auch Oracle) füllt mitnichten Lücken auf!</p>
<p>Ebenso muß mann sich bei MySQL nicht darum scheren ob eine ID schon belegt ist &#8211; diese wird dann beim insert übersprungen, das allerdings geht mit Sequenzen wie sie Oracle verwendet natürlich nicht.</p>
<p>Eine Sorge weniger&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://drittenormalform.de/wordpress/2009/07/08/autoincrement-verhalten-in-mysql/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

