{"id":2001,"date":"2016-09-13T16:30:00","date_gmt":"2016-09-13T14:30:00","guid":{"rendered":"https:\/\/www.sqlinthewild.co.za\/?p=2001"},"modified":"2016-09-13T09:51:19","modified_gmt":"2016-09-13T07:51:19","slug":"what-is-a-sargable-predicate","status":"publish","type":"post","link":"https:\/\/www.sqlinthewild.co.za\/index.php\/2016\/09\/13\/what-is-a-sargable-predicate\/","title":{"rendered":"What is a SARGable predicate?"},"content":{"rendered":"<p>\u2018SARGable\u2019 is a weird term. It gets bandied around a lot when talking about indexes and whether queries can seek on indexes. The term\u2019s an abbreviation, \u2018SARG\u2019 stands for Search ARGument, and it means that the predicate can be executed using an index seek.<\/p>\n<p>Lovely. So a predicate must be SARGable to be able to use an index seek, and it must be able to use an index seek to be SARGable. A completely circular definition.<\/p>\n<p>So what does it actually mean for a predicate to be SARGable? (and we\u2019ll assume for this discussion that there are suitable indexes available)<\/p>\n<p>The most general form for a predicate is &lt;expression&gt; &lt;operator&gt; &lt;expression&gt;. To be SARGable, a predicate must, on one side, have a column, not an expression on a column. So, &lt;column&gt; &lt;operator&gt; &lt;expression&gt;<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">SELECT * FROM Numbers\r\nWHERE Number = 42;<\/pre>\n<p><a href=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek1.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Seek1\" src=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek1_thumb.png\" alt=\"Seek1\" width=\"431\" height=\"131\" border=\"0\" \/><\/a><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">SELECT * FROM Numbers\r\nWHERE Number + 0 = 42;<\/pre>\n<p><a href=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Scan1.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Scan1\" src=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Scan1_thumb.png\" alt=\"Scan1\" width=\"433\" height=\"132\" border=\"0\" \/><\/a><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">SELECT * FROM Numbers\r\nWHERE Number = 42 + 0;<\/pre>\n<p><a href=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek2.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Seek2\" src=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek2_thumb.png\" alt=\"Seek2\" width=\"441\" height=\"158\" border=\"0\" \/><\/a><\/p>\n<p>Any<sup>1<\/sup> function on a column will prevent an index seek from happening, even if the function would not change the column\u2019s value or the way the operator is applied, as seen in the above case. Zero added to an integer doesn\u2019t change the value of the column, but is still sufficient to prevent an index seek operation from happening.<\/p>\n<p>While I haven\u2019t yet found any production code where the predicate is of the form \u2018Column + 0\u2019 = @Value\u2019, I have seen many cases where there are less obvious cases of functions on columns that do nothing other than to prevent index seeks.<\/p>\n<p>UPPER(Column) = UPPER(@Variable) in a case-insensitive database is one of them, RTRIM(COLUMN) = @Variable is another. SQL ignores trailing spaces when comparing strings.<\/p>\n<p>The other requirement for a predicate to be SARGable, for SQL Server at least, is that the column and expression are of the same data type or, if the data types differ, such that the expression will be implicitly converted to the data type of the column.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">SELECT 1 FROM SomeTable\r\nWHERE StringColumn = 0;<\/pre>\n<p><a href=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Scan2.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Scan2\" src=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Scan2_thumb.png\" alt=\"Scan2\" width=\"453\" height=\"123\" border=\"0\" \/><\/a><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">SELECT 1 FROM SomeTable\r\nWHERE StringColumn = \u20180\u2019;<\/pre>\n<p><a href=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek3.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Seek3\" src=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek3_thumb.png\" alt=\"Seek3\" width=\"453\" height=\"119\" border=\"0\" \/><\/a><\/p>\n<p>There are some exceptions here. Comparing a DATE column to a DATETIME value would normally implicitly convert the column to DATETIME (more precise data type), but that doesn\u2019t cause index scans. Neither does comparing an ascii column to a unicode string, at least in some collations.<\/p>\n<p>In generally though, conversions should be explicit and decided on by the developer, not left up to what SQL server decides.<\/p>\n<p>What about operators?<\/p>\n<p>The majority are fine. Equality, Inequality, IN (with a list of values), IS NULL all allow index usage. EXIST and IN with a subquery are treated like joins, which may or may not use indexes depending on the join type chosen.<\/p>\n<p>LIKE is a slight special case. Predicates with LIKE are only SARGable if the wildcard is not at the start of the string.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">SELECT 1 FROM SomeStrings\r\nWHERE ASCIIString LIKE 'A%'<\/pre>\n<p><a href=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek4.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Seek4\" src=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek4_thumb.png\" alt=\"Seek4\" width=\"465\" height=\"123\" border=\"0\" \/><\/a><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">SELECT 1 FROM SomeStrings\r\nWHERE ASCIIString LIKE '%A'<\/pre>\n<p><a href=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Scan3.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Scan3\" src=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Scan3_thumb.png\" alt=\"Scan3\" width=\"451\" height=\"103\" border=\"0\" \/><\/a><\/p>\n<p>There are blog posts that claim that adding NOT makes a predicate non-SARGable. In the general case that\u2019s not true.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">SELECT * FROM Numbers\r\nWHERE NOT Number &gt; 100;<\/pre>\n<p><a href=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek5.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Seek5\" src=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek5_thumb.png\" alt=\"Seek5\" width=\"392\" height=\"101\" border=\"0\" \/><\/a><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">SELECT * FROM Numbers\r\nWHERE NOT Number &lt;= 100;<\/pre>\n<p><a href=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek6.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Seek6\" src=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek6_thumb.png\" alt=\"Seek6\" width=\"404\" height=\"119\" border=\"0\" \/><\/a><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">SELECT * FROM Numbers\r\nWHERE NOT Number = 137;<\/pre>\n<p><a href=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek7.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;\" title=\"Seek7\" src=\"https:\/\/www.sqlinthewild.co.za\/wp-content\/uploads\/2016\/09\/Seek7_thumb.png\" alt=\"Seek7\" width=\"484\" height=\"84\" border=\"0\" \/><\/a><\/p>\n<p>These index seeks are returning most of the table, but there\u2019s nothing in the definition of \u2018SARGable\u2019 that requires small portions of the table to be returned.<\/p>\n<p>That\u2019s mostly that for SARGable in SQL Server. It\u2019s mostly about having no functions on the column and no implicit conversions of the column.<\/p>\n<p>(1) An explicit CAST of a DATE column to DATETIME still leaves the predicate SARGable. This is an exception that\u2019s been specifically coded into the optimiser.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u2018SARGable\u2019 is a weird term. It gets bandied around a lot when talking about indexes and whether queries can seek on indexes. The term\u2019s an abbreviation, \u2018SARG\u2019 stands for Search ARGument, and it means that the predicate can be executed&#8230; <a class=\"read-more-button\" href=\"https:\/\/www.sqlinthewild.co.za\/index.php\/2016\/09\/13\/what-is-a-sargable-predicate\/\">(Read more)<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"New blog post: What is a SARGable predicate?","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[25,15,16,17],"tags":[],"class_list":["post-2001","post","type-post","status-publish","format-standard","hentry","category-performance","category-sql-server","category-syndication","category-t-sql"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p7h6n-wh","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts\/2001","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/comments?post=2001"}],"version-history":[{"count":7,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts\/2001\/revisions"}],"predecessor-version":[{"id":2008,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts\/2001\/revisions\/2008"}],"wp:attachment":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/media?parent=2001"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/categories?post=2001"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/tags?post=2001"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}