Weird query plan

  • I'm stuck on a query I don't seem to be able to tune.

    Everything seems to be related to a predicate on the replication function ISPALUSER.

    Here's my query:

    SELECT [SALES_AGENCY].[IdSalesAgency],

    [SALES_AGENCY].[SalesAgencyCode],

    msp.partition_id

    FROM [dbo].[SALES_AGENCY] [SALES_AGENCY],

    dbo.MSmerge_partition_groups msp

    WHERE (msp.publication_number = 1

    AND ((([SalesAgencyCode] = msp.[HOST_NAME_FN] )))

    )

    AND ({fn ISPALUSER('23320088-BB3F-46AC-905D-0F2A95181934')} = 1

    OR PERMISSIONS(404912514) & 0x1b <> 0

    )

    This is the table script for SALES_AGENCY (user table):

    CREATE TABLE [dbo].[SALES_AGENCY](

    [IdSalesAgency] uniqueidentifier ROWGUIDCOL NOT NULL PRIMARY KEY CLUSTERED,

    [SalesAgencyCode] nvarchar(25) NOT NULL,

    [Description] nvarchar(200) NOT NULL,

    [IdLanguage] uniqueidentifier NOT NULL,

    [IdAddress] uniqueidentifier NOT NULL,

    [Status] nvarchar(3) NOT NULL,

    CONSTRAINT [AK_UK_SALES_AGENCY_SALES_AG] UNIQUE NONCLUSTERED

    (

    [SalesAgencyCode] ASC,

    [IdSalesAgency] ASC

    )

    )

    And this is the table script for MSmerge_partition_groups (system table, created during merge replication setup):

    CREATE TABLE [dbo].[MSmerge_partition_groups](

    [partition_id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED ,

    [publication_number] [smallint] NOT NULL,

    [maxgen_whenadded] [bigint] NULL,

    [using_partition_groups] [bit] NULL,

    [is_partition_active] [bit] NOT NULL,

    [HOST_NAME_FN] [nvarchar](260) NULL,

    )

    CREATE NONCLUSTERED INDEX [ncMSmerge_partition_groups_HOST_NAME_FN] ON [dbo].[MSmerge_partition_groups]

    (

    [HOST_NAME_FN] ASC

    )

    CREATE NONCLUSTERED INDEX [nc1MSmerge_partition_groups] ON [dbo].[MSmerge_partition_groups]

    (

    [publication_number] ASC,

    [HOST_NAME_FN] ASC

    )

    I don't understand why I get a different (and suboptimal) plan when the replication predicates are added to the query, while I get a nice seek + nesteed loop plan leaving out the repl predicates.

    I linked the two plans:

    http://sqlconsulting.it/static/with_repl_predicates.sqlplan

    http://sqlconsulting.it/static/without_repl_predicates.sqlplan

    Can anyone shed some light?

    How can

    AND ({fn ISPALUSER('23320088-BB3F-46AC-905D-0F2A95181934')} = 1

    OR PERMISSIONS(404912514) & 0x1b <> 0

    )

    change the plan so deeply?

    -- Gianluca Sartori

  • I don't see ISPALUSER in BOL. Can you script that function out for me?

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • Gianluca Sartori (12/1/2010)


    How can

    AND ({fn ISPALUSER('23320088-BB3F-46AC-905D-0F2A95181934')} = 1

    OR PERMISSIONS(404912514) & 0x1b <> 0

    )

    change the plan so deeply?

    Look at the order of your parens, ANDs, and ORs.

    I think it's counting & as a bitwise And.

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • Yup. It is not my code, anyway. This has been generated by the merge replication setup.

    I find lots of (system) views with this filter, named msmerge_whatever.

    What I don't understand is why this filter, that doesn't seem to be related to data in the tables, forces an index scan.

    fn ISPALUSER('23320088-BB3F-46AC-905D-0F2A95181934')} = 1

    checks if current user is in the replication role (MSmerge_PAL_role)

    PERMISSIONS(404912514) & 0x1b <> 0

    checks if user has permissions on object

    None of these predicates need to access the tables, so why a scan?

    -- Gianluca Sartori

  • Brandie Tarvin (12/1/2010)


    I don't see ISPALUSER in BOL. Can you script that function out for me?

    ISPALUSER Deep Dive

    Wayne
    Microsoft Certified Master: SQL Server 2008
    Author - SQL Server T-SQL Recipes


    If you can't explain to another person how the code that you're copying from the internet works, then DON'T USE IT on a production system! After all, you will be the one supporting it!
    Links:
    For better assistance in answering your questions
    Performance Problems
    Common date/time routines
    Understanding and Using APPLY Part 1 & Part 2

  • Gianluca Sartori (12/1/2010)


    None of these predicates need to access the tables, so why a scan?

    Because you've got them all lumped together??? To my eyes, the code should say:

    AND ({fn ISPALUSER('23320088-BB3F-46AC-905D-0F2A95181934')} = 1

    OR ( PERMISSIONS(404912514) & 0x1b <> 0)

    )

    Or am I misunderstanding the WHERE clause?

    EDIT FYI: When I try to look at your plans, I get the following error: "The XML page cannot be displayed

    Cannot view XML input using style sheet. Please correct the error and then click the Refresh button, or try again later.

    --------------------------------------------------------------------------------

    Switch from current encoding to specified encoding not supported. Error processing resource 'http://sqlconsulting.it/static...

    <?xml version="1.0" encoding="utf-16"?>"

    ...I'm also reading up on that function now.

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • Brandie Tarvin (12/1/2010)


    Gianluca Sartori (12/1/2010)


    None of these predicates need to access the tables, so why a scan?

    Because you've got them all lumped together??? To my eyes, the code should say:

    AND ({fn ISPALUSER('23320088-BB3F-46AC-905D-0F2A95181934')} = 1

    OR ( PERMISSIONS(404912514) & 0x1b <> 0)

    )

    Or am I misunderstanding the WHERE clause?

    Thanks, Brandie. Anyway, I don't think that adding the parentheses that way can change the expression.

    However, it's not my code, it's Microsoft's. I can't change it, I just have to deal with it and (hopefully) understand and tune it.

    Try looking at the query plan for:

    SELECT 1

    WHERE ({fn ISPALUSER('23320088-BB3F-46AC-905D-0F2A95181934')} = 1

    OR ( PERMISSIONS(404912514) & 0x1b <> 0)

    )

    You will see just a constant scan and a filter. No tables, no indexes accessed.

    Why does it force a scan on my index?

    -- Gianluca Sartori

  • Brandie Tarvin (12/1/2010)


    EDIT FYI: When I try to look at your plans, I get the following error: "The XML page cannot be displayed

    Cannot view XML input using style sheet. Please correct the error and then click the Refresh button, or try again later.

    Thanks for pointing it out. Try right-clicking and "save as...". The browser seems to detect it's an XML file and tries to display it instead of opening it with SSMS.

    I uploaded them to my personal site because attachments don't work for me on SSC. Go figure.

    -- Gianluca Sartori

  • WayneS (12/1/2010)


    Brandie Tarvin (12/1/2010)


    I don't see ISPALUSER in BOL. Can you script that function out for me?

    ISPALUSER Deep Dive

    Thank you, Wayne!

    It also took me to Paul Ibson's site, that looks pretty cool.

    Unfortunately, it doesn't solve my issue. :crying:

    -- Gianluca Sartori

  • Maybe you have the plans misnamed, but "Without_repl_predicates" shows an Index scan (IndexScan Ordered="true") and the other plan shows the opposite??

    Anyway, while I'm playing with this, try doing the first statement without the second. And the second statement without the first. See if there's any change.

    Also, take heed that PERMISSIONS() is deprecated. Take a shot at using FN_MY_PERMISSIONS or HAS_PERMS_BY_NAME instead. See what that does to your query plan.

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • I tried downloading the plans from the URLs in my first post and they contain:

    with_repl_predicates.sqlplan --> index scan

    without_repl_predicates.sqlplan --> index seek

    I already tried running the query without the ISPALUSER and without the PERMISSIONS parts. Nothing changed.

    I know that PERMISSIONS is deprecated, but I cannot change it.

    -- Gianluca Sartori

  • Gianluca Sartori (12/1/2010)


    WayneS (12/1/2010)


    Brandie Tarvin (12/1/2010)


    I don't see ISPALUSER in BOL. Can you script that function out for me?

    ISPALUSER Deep Dive

    Thank you, Wayne!

    It also took me to Paul Ibson's site, that looks pretty cool.

    Unfortunately, it doesn't solve my issue. :crying:

    It is kinda surprising - as thorough as that blog is, and it didn't cover performance or query plans.

    You might be able to plan around with generating the query plan without the function calls, and then store that plan for use by these queries?

    Wayne
    Microsoft Certified Master: SQL Server 2008
    Author - SQL Server T-SQL Recipes


    If you can't explain to another person how the code that you're copying from the internet works, then DON'T USE IT on a production system! After all, you will be the one supporting it!
    Links:
    For better assistance in answering your questions
    Performance Problems
    Common date/time routines
    Understanding and Using APPLY Part 1 & Part 2

  • WayneS (12/1/2010)


    You might be able to plan around with generating the query plan without the function calls, and then store that plan for use by these queries?

    I don't know how I could do it. Plan guides?

    Unfortunately I can't play with hints or the like, beacause I can't modify the views.

    -- Gianluca Sartori

  • Maybe I'm off base here, but could the scan be caused by SQL Server pulling the data and then checking the permissions for each record to see if the user has the perms to see it? Instead of checking the permissions once and being done?

    If you could alter that, I'd recommend testing by creating an IF statement to check the perms before doing the query. But if you can't change any of that, then the suggestion is useless. Still, it might be an interesting thing to see what the execution plan says in that particular case.

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • Gianluca Sartori (12/1/2010)


    WayneS (12/1/2010)


    You might be able to plan around with generating the query plan without the function calls, and then store that plan for use by these queries?

    I don't know how I could do it. Plan guides?

    Unfortunately I can't play with hints or the like, beacause I can't modify the views.

    Yes, Plan Guides is what I was thinking about. I haven't used them, but I believe that you can assign them to queries, and then those queries use that plan guide. Not sure if it would even work in this case.

    Wayne
    Microsoft Certified Master: SQL Server 2008
    Author - SQL Server T-SQL Recipes


    If you can't explain to another person how the code that you're copying from the internet works, then DON'T USE IT on a production system! After all, you will be the one supporting it!
    Links:
    For better assistance in answering your questions
    Performance Problems
    Common date/time routines
    Understanding and Using APPLY Part 1 & Part 2

Viewing 15 posts - 1 through 14 (of 14 total)

You must be logged in to reply to this topic. Login to reply